src/pgp_netpgp.c
author Edouard Tisserant
Wed, 13 May 2015 00:08:20 +0200
changeset 277 5c8838004648
parent 276 73d4c99cf054
child 279 99e9815751fa
permissions -rw-r--r--
netpgp : send_keys without curl POST. Still need to fix import to avoid duplicates
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
Edouard@174
     8
#include <netpgp.h>
Edouard@179
     9
#include <netpgp/config.h>
Edouard@179
    10
#include <netpgp/memory.h>
Edouard@179
    11
#include <netpgp/crypto.h>
Edouard@180
    12
#include <netpgp/netpgpsdk.h>
Edouard@180
    13
#include <netpgp/validate.h>
Edouard@228
    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@174
    35
Edouard@263
    36
    if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
Edouard@263
    37
        setlocale(LC_ALL, "");
Edouard@174
    38
Edouard@263
    39
    memset(&netpgp, 0x0, sizeof(netpgp_t));
Edouard@180
    40
Edouard@263
    41
    // netpgp_setvar(&netpgp, "max mem alloc", "4194304");
Edouard@263
    42
    netpgp_setvar(&netpgp, "need seckey", "1");
Edouard@263
    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@175
    65
Edouard@252
    66
unlock_netpgp:
Edouard@252
    67
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@263
    68
    
Edouard@263
    69
    return status;
Edouard@263
    70
}
Edouard@175
    71
Edouard@263
    72
static void release_netpgp()
Edouard@263
    73
{
Edouard@263
    74
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@263
    75
        return;
Edouard@263
    76
    }
Edouard@263
    77
    netpgp_end(&netpgp);
Edouard@263
    78
    memset(&netpgp, 0x0, sizeof(netpgp_t));
Edouard@263
    79
Edouard@263
    80
    pthread_mutex_destroy(&netpgp_mutex);
Edouard@263
    81
Edouard@263
    82
    return;
Edouard@263
    83
}
Edouard@263
    84
Edouard@263
    85
static PEP_STATUS init_curl(
Edouard@263
    86
    CURL **curl,
Edouard@263
    87
    pthread_mutex_t *curl_mutex,
Edouard@263
    88
    bool in_first)
Edouard@263
    89
{
Edouard@263
    90
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@263
    91
    struct curl_slist *headers=NULL;
Edouard@263
    92
Edouard@263
    93
    if(pthread_mutex_init(curl_mutex, NULL)){
Edouard@263
    94
        return PEP_OUT_OF_MEMORY;
Edouard@263
    95
    }
Edouard@263
    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@263
   105
    if ((*curl = curl_easy_init()) == NULL) {
Edouard@263
   106
        return PEP_OUT_OF_MEMORY;
Edouard@263
   107
    }
Edouard@263
   108
Edouard@263
   109
    curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
Edouard@263
   110
    curl_easy_setopt(*curl, CURLOPT_MAXREDIRS, 3L);
Edouard@263
   111
Edouard@263
   112
    headers=curl_slist_append(headers,"Pragma: no-cache");
Edouard@263
   113
    if(headers)
Edouard@263
   114
        headers=curl_slist_append(headers,"Cache-Control: no-cache");
Edouard@263
   115
Edouard@263
   116
    if(!headers)
Edouard@263
   117
    {
Edouard@263
   118
        status = PEP_OUT_OF_MEMORY;
Edouard@263
   119
        goto unlock_curl;
Edouard@174
   120
    }
Edouard@174
   121
Edouard@263
   122
    curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
Edouard@263
   123
    curl_slist_free_all(headers);
Edouard@263
   124
Edouard@263
   125
    // TODO curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
Edouard@263
   126
Edouard@263
   127
unlock_curl:
Edouard@263
   128
    pthread_mutex_unlock(curl_mutex);
Edouard@174
   129
    return status;
Edouard@174
   130
}
Edouard@174
   131
Edouard@263
   132
static void release_curl(
Edouard@263
   133
    CURL **curl,
Edouard@263
   134
    pthread_mutex_t *curl_mutex, 
Edouard@263
   135
    bool out_last)
Edouard@263
   136
{
Edouard@263
   137
    if(pthread_mutex_lock(curl_mutex)){
Edouard@263
   138
        return;
Edouard@263
   139
    }
Edouard@263
   140
Edouard@263
   141
    if(*curl)
Edouard@263
   142
        curl_easy_cleanup(*curl);
Edouard@263
   143
Edouard@263
   144
    *curl = NULL;
Edouard@263
   145
Edouard@263
   146
    if(out_last){
Edouard@263
   147
        curl_global_cleanup();
Edouard@263
   148
    }
Edouard@263
   149
Edouard@263
   150
    pthread_mutex_destroy(curl_mutex);
Edouard@263
   151
Edouard@263
   152
    return;
Edouard@263
   153
}
Edouard@263
   154
Edouard@263
   155
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
Edouard@263
   156
{
Edouard@263
   157
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@263
   158
Edouard@263
   159
    assert(session);
Edouard@263
   160
    if(!session) return PEP_UNKNOWN_ERROR;
Edouard@263
   161
Edouard@263
   162
    if (in_first) {
Edouard@263
   163
        if((status = init_netpgp()) != PEP_STATUS_OK)
Edouard@263
   164
        return status;
Edouard@263
   165
    }
Edouard@263
   166
Edouard@263
   167
    if((status = init_curl(
Edouard@263
   168
                    &session->ctx.curl,
Edouard@263
   169
                    &session->ctx.curl_mutex,
Edouard@263
   170
                    in_first) != PEP_STATUS_OK)){
Edouard@263
   171
        if(in_first) release_netpgp();
Edouard@263
   172
        return status;
Edouard@263
   173
    }
Edouard@263
   174
Edouard@263
   175
    return PEP_STATUS_OK;
Edouard@263
   176
}
Edouard@263
   177
Edouard@174
   178
void pgp_release(PEP_SESSION session, bool out_last)
Edouard@174
   179
{
Edouard@179
   180
    assert(session);
Edouard@179
   181
    if(!session) return;
Edouard@179
   182
Edouard@263
   183
    if (out_last){
Edouard@263
   184
        release_netpgp();
Edouard@252
   185
    }
Edouard@263
   186
    release_curl(&session->ctx.curl, &session->ctx.curl_mutex, out_last);
Edouard@174
   187
}
Edouard@174
   188
Edouard@207
   189
// return 1 if the file contains ascii-armoured text 
Edouard@207
   190
// buf MUST be \0 terminated to be checked for armour
Edouard@188
   191
static unsigned
Edouard@188
   192
_armoured(const char *buf, size_t size, const char *pattern)
Edouard@188
   193
{
Edouard@188
   194
    unsigned armoured = 0;
Edouard@188
   195
    if(buf[size]=='\0'){
Edouard@188
   196
        regex_t r;
Edouard@188
   197
        regcomp(&r, pattern, REG_EXTENDED|REG_NEWLINE|REG_NOSUB);
Edouard@188
   198
        if (regexec(&r, buf, 0, NULL, 0) == 0) {
Edouard@188
   199
            armoured = 1;
Edouard@188
   200
        }
Edouard@188
   201
        regfree(&r);
Edouard@188
   202
    }
Edouard@188
   203
    return armoured;
Edouard@188
   204
}
Edouard@188
   205
Edouard@227
   206
/* return key ID's hexdump as a string */
Edouard@227
   207
static void id_to_str(const uint8_t *userid, char *fpr)
Edouard@225
   208
{
Edouard@225
   209
    int i;
Edouard@225
   210
    static const char *hexes = "0123456789abcdef";
Edouard@225
   211
    for (i = 0; i < 8 ; i++) {
Edouard@225
   212
        fpr[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
Edouard@225
   213
        fpr[(i * 2) + 1] = hexes[userid[i] & 0xf];
Edouard@225
   214
    }
Edouard@225
   215
    fpr[8 * 2] = 0x0;
Edouard@225
   216
}
Edouard@225
   217
Edouard@185
   218
// Iterate through netpgp' reported valid signatures 
Edouard@185
   219
// fill a list of valid figerprints
Edouard@185
   220
// returns PEP_STATUS_OK if all sig reported valid
Edouard@185
   221
// error status otherwise.
Edouard@185
   222
static PEP_STATUS _validation_results(netpgp_t *netpgp, pgp_validation_t *vresult,
Edouard@185
   223
                                             stringlist_t **_keylist)
Edouard@185
   224
{
Edouard@188
   225
    time_t    now;
Edouard@188
   226
    time_t    t;
Edouard@188
   227
    char    buf[128];
Edouard@185
   228
Edouard@188
   229
    now = time(NULL);
Edouard@188
   230
    if (now < vresult->birthtime) {
Edouard@188
   231
        // signature is not valid yet
Edouard@188
   232
        return PEP_UNENCRYPTED;
Edouard@188
   233
    }
Edouard@188
   234
    if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
Edouard@188
   235
        // signature has expired
Edouard@188
   236
        t = vresult->duration + vresult->birthtime;
Edouard@188
   237
        return PEP_UNENCRYPTED;
Edouard@188
   238
    }
Edouard@185
   239
    if (vresult->validc && vresult->valid_sigs &&
Edouard@185
   240
        !vresult->invalidc && !vresult->unknownc ) {
Edouard@185
   241
        unsigned    n;
Edouard@185
   242
        stringlist_t *k;
Edouard@185
   243
        // caller responsible to free
Edouard@185
   244
        *_keylist = new_stringlist(NULL);
Edouard@185
   245
        assert(*_keylist);
Edouard@185
   246
        if (*_keylist == NULL) {
Edouard@185
   247
            return PEP_OUT_OF_MEMORY;
Edouard@185
   248
        }
Edouard@185
   249
        k = *_keylist;
Edouard@185
   250
        for (n = 0; n < vresult->validc; ++n) {
Edouard@185
   251
            char id[MAX_ID_LENGTH + 1];
Edouard@185
   252
            const uint8_t *userid = vresult->valid_sigs[n].signer_id;
Edouard@185
   253
Edouard@227
   254
            id_to_str(userid, id);
Edouard@185
   255
Edouard@185
   256
            k = stringlist_add(k, id);
Edouard@185
   257
            if(!k){
Edouard@185
   258
                free_stringlist(*_keylist);
Edouard@185
   259
                return PEP_OUT_OF_MEMORY;
Edouard@185
   260
            }
Edouard@185
   261
        }
Edouard@185
   262
        return PEP_STATUS_OK;
Edouard@185
   263
    }
Edouard@185
   264
    if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
Edouard@185
   265
        // No signatures found - is this memory signed?
Edouard@185
   266
        return PEP_VERIFY_NO_KEY; 
Edouard@185
   267
    } 
Edouard@185
   268
    
Edouard@185
   269
    if (vresult->invalidc) {
Edouard@185
   270
        // some invalid signatures
Edouard@185
   271
        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@185
   272
    }
Edouard@185
   273
    
Edouard@185
   274
    // only unknown sigs
Edouard@185
   275
    return PEP_DECRYPT_WRONG_FORMAT;
Edouard@185
   276
}
Edouard@185
   277
Edouard@207
   278
#define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----\\s*$"
Edouard@174
   279
PEP_STATUS pgp_decrypt_and_verify(
Edouard@174
   280
    PEP_SESSION session, const char *ctext, size_t csize,
Edouard@174
   281
    char **ptext, size_t *psize, stringlist_t **keylist
Edouard@174
   282
    )
Edouard@174
   283
{
Edouard@185
   284
    pgp_memory_t *mem;
Edouard@185
   285
    pgp_memory_t *cat;
Edouard@185
   286
    pgp_validation_t *vresult;
Edouard@180
   287
    char *_ptext = NULL;
Edouard@180
   288
    size_t _psize = 0;
Edouard@185
   289
    int ret;
Edouard@179
   290
Edouard@174
   291
    PEP_STATUS result;
Edouard@174
   292
    stringlist_t *_keylist = NULL;
Edouard@174
   293
    int i_key = 0;
Edouard@174
   294
Edouard@174
   295
    assert(session);
Edouard@174
   296
    assert(ctext);
Edouard@174
   297
    assert(csize);
Edouard@174
   298
    assert(ptext);
Edouard@174
   299
    assert(psize);
Edouard@174
   300
    assert(keylist);
Edouard@174
   301
Edouard@179
   302
    if(!session || !ctext || !csize || !ptext || !psize || !keylist) 
Edouard@179
   303
        return PEP_UNKNOWN_ERROR;
Edouard@179
   304
Edouard@263
   305
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   306
        return PEP_UNKNOWN_ERROR;
Edouard@252
   307
    }
Edouard@179
   308
Edouard@174
   309
    *ptext = NULL;
Edouard@174
   310
    *psize = 0;
Edouard@174
   311
    *keylist = NULL;
Edouard@174
   312
Edouard@183
   313
    vresult = malloc(sizeof(pgp_validation_t));
Edouard@185
   314
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@182
   315
Edouard@252
   316
    mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
Edouard@252
   317
                netpgp.secring, netpgp.pubring,
Edouard@188
   318
                _armoured(ctext, csize, ARMOR_HEAD),
Edouard@179
   319
                0 /* sshkeys */,
Edouard@180
   320
                NULL, -1, NULL  /* pass fp,attempts,cb */);
Edouard@179
   321
    if (mem == NULL) {
Edouard@252
   322
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   323
        goto unlock_netpgp;
Edouard@179
   324
    }
Edouard@179
   325
Edouard@185
   326
    _psize = pgp_mem_len(mem);
Edouard@182
   327
    if (_psize){
Edouard@272
   328
        if ((_ptext = malloc(_psize + 1)) == NULL) {
Edouard@183
   329
            result = PEP_OUT_OF_MEMORY;
Edouard@183
   330
            goto free_pgp;
Edouard@182
   331
        }
Edouard@185
   332
        memcpy(_ptext, pgp_mem_data(mem), _psize);
Edouard@272
   333
        _ptext[_psize] = '\0'; // safeguard for naive users
Edouard@182
   334
        result = PEP_DECRYPTED;
Edouard@182
   335
    }else{
Edouard@183
   336
        result = PEP_DECRYPT_NO_KEY;
Edouard@183
   337
        goto free_pgp;
Edouard@182
   338
    }
Edouard@180
   339
Edouard@185
   340
    if (result == PEP_DECRYPTED) {
Edouard@252
   341
        result = _validation_results(&netpgp, vresult, &_keylist);
Edouard@185
   342
        if (result != PEP_STATUS_OK) {
Edouard@185
   343
            goto free_ptext;
Edouard@183
   344
        }
Edouard@180
   345
        result = PEP_DECRYPTED_AND_VERIFIED;
Edouard@180
   346
    }
Edouard@174
   347
Edouard@180
   348
    if (result == PEP_DECRYPTED_AND_VERIFIED
Edouard@180
   349
        || result == PEP_DECRYPTED) {
Edouard@180
   350
        *ptext = _ptext;
Edouard@180
   351
        *psize = _psize;
Edouard@180
   352
        (*ptext)[*psize] = 0; // safeguard for naive users
Edouard@185
   353
        if (result == PEP_DECRYPTED_AND_VERIFIED) {
Edouard@185
   354
            *keylist = _keylist;
Edouard@185
   355
        }
Edouard@183
   356
Edouard@183
   357
        /* _ptext and _keylist ownership transfer, don't free */
Edouard@183
   358
        goto free_pgp;
Edouard@180
   359
    }
Edouard@183
   360
Edouard@183
   361
free_keylist:
Edouard@183
   362
    free_stringlist(_keylist);
Edouard@183
   363
Edouard@183
   364
free_ptext:
Edouard@183
   365
    free(_ptext);
Edouard@183
   366
Edouard@183
   367
free_pgp:
Edouard@185
   368
    pgp_memory_free(mem);
Edouard@183
   369
    pgp_validate_result_free(vresult);
Edouard@183
   370
Edouard@252
   371
unlock_netpgp:
Edouard@252
   372
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   373
Edouard@174
   374
    return result;
Edouard@174
   375
}
Edouard@174
   376
Edouard@207
   377
#define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----\\s*$"
Edouard@174
   378
PEP_STATUS pgp_verify_text(
Edouard@174
   379
    PEP_SESSION session, const char *text, size_t size,
Edouard@174
   380
    const char *signature, size_t sig_size, stringlist_t **keylist
Edouard@174
   381
    )
Edouard@174
   382
{
Edouard@185
   383
    pgp_memory_t *signedmem;
Edouard@185
   384
    pgp_memory_t *sig;
Edouard@185
   385
    pgp_validation_t *vresult;
Edouard@185
   386
Edouard@174
   387
    PEP_STATUS result;
Edouard@174
   388
    stringlist_t *_keylist;
Edouard@174
   389
Edouard@174
   390
    assert(session);
Edouard@174
   391
    assert(text);
Edouard@174
   392
    assert(size);
Edouard@174
   393
    assert(signature);
Edouard@174
   394
    assert(sig_size);
Edouard@174
   395
    assert(keylist);
Edouard@174
   396
Edouard@185
   397
    if(!session || !text || !size || !signature || !sig_size || !keylist) 
Edouard@185
   398
        return PEP_UNKNOWN_ERROR;
Edouard@185
   399
Edouard@263
   400
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   401
        return PEP_UNKNOWN_ERROR;
Edouard@252
   402
    }
Edouard@185
   403
Edouard@174
   404
    *keylist = NULL;
Edouard@185
   405
Edouard@185
   406
    vresult = malloc(sizeof(pgp_validation_t));
Edouard@276
   407
    if (vresult == NULL) {
Edouard@276
   408
        result = PEP_OUT_OF_MEMORY;
Edouard@276
   409
        goto unlock_netpgp;
Edouard@276
   410
    }
Edouard@185
   411
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@185
   412
Edouard@185
   413
    signedmem = pgp_memory_new();
Edouard@185
   414
    if (signedmem == NULL) {
Edouard@252
   415
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   416
        goto unlock_netpgp;
Edouard@185
   417
    }
Edouard@185
   418
    pgp_memory_add(signedmem, (const uint8_t*)text, size);
Edouard@185
   419
Edouard@185
   420
    sig = pgp_memory_new();
Edouard@185
   421
    if (sig == NULL) {
Edouard@185
   422
        pgp_memory_free(signedmem);
Edouard@252
   423
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   424
        goto unlock_netpgp;
Edouard@185
   425
    }
Edouard@185
   426
    pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
Edouard@185
   427
Edouard@252
   428
    pgp_validate_mem_detached(netpgp.io, vresult, sig,
Edouard@185
   429
                NULL,/* output */
Edouard@207
   430
                _armoured(signature, sig_size, ARMOR_SIG_HEAD),
Edouard@252
   431
                netpgp.pubring,
Edouard@185
   432
                signedmem);
Edouard@185
   433
Edouard@252
   434
    result = _validation_results(&netpgp, vresult, &_keylist);
Edouard@185
   435
    if (result != PEP_STATUS_OK) {
Edouard@185
   436
        goto free_pgp;
Edouard@185
   437
    }else{
Edouard@185
   438
        result = PEP_VERIFIED;
Edouard@185
   439
    }
Edouard@185
   440
Edouard@185
   441
    if (result == PEP_VERIFIED) {
Edouard@185
   442
        /* TODO : check trust level */
Edouard@185
   443
        result = PEP_VERIFIED_AND_TRUSTED;
Edouard@185
   444
    }
Edouard@185
   445
Edouard@185
   446
    if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
Edouard@185
   447
        *keylist = _keylist;
Edouard@185
   448
Edouard@185
   449
        /* _keylist ownership transfer, don't free */
Edouard@185
   450
        goto free_pgp;
Edouard@185
   451
    }
Edouard@185
   452
Edouard@185
   453
free_keylist:
Edouard@185
   454
    free_stringlist(_keylist);
Edouard@185
   455
Edouard@185
   456
free_pgp:
Edouard@187
   457
    // free done by pgp_validate_mem_detached
Edouard@187
   458
    // pgp_memory_free(sig);
Edouard@187
   459
    // pgp_memory_free(signedmem);
Edouard@185
   460
    pgp_validate_result_free(vresult);
Edouard@185
   461
Edouard@252
   462
unlock_netpgp:
Edouard@252
   463
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   464
Edouard@185
   465
    return result;
Edouard@174
   466
}
Edouard@174
   467
Edouard@174
   468
PEP_STATUS pgp_encrypt_and_sign(
Edouard@174
   469
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
Edouard@174
   470
    size_t psize, char **ctext, size_t *csize
Edouard@174
   471
    )
Edouard@174
   472
{
Edouard@207
   473
    const pgp_key_t *keypair;
Edouard@207
   474
    pgp_seckey_t *seckey;
Edouard@209
   475
    pgp_memory_t *signedmem;
Edouard@209
   476
    pgp_memory_t *cmem;
Edouard@207
   477
    const char *userid;
Edouard@207
   478
    const char *hashalg;
Edouard@209
   479
    pgp_keyring_t *rcpts;
Edouard@207
   480
Edouard@174
   481
    PEP_STATUS result;
Edouard@174
   482
    const stringlist_t *_keylist;
Edouard@174
   483
Edouard@174
   484
    assert(session);
Edouard@174
   485
    assert(keylist);
Edouard@174
   486
    assert(ptext);
Edouard@174
   487
    assert(psize);
Edouard@174
   488
    assert(ctext);
Edouard@174
   489
    assert(csize);
Edouard@174
   490
Edouard@207
   491
    if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
Edouard@207
   492
        return PEP_UNKNOWN_ERROR;
Edouard@207
   493
Edouard@263
   494
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   495
        return PEP_UNKNOWN_ERROR;
Edouard@252
   496
    }
Edouard@208
   497
Edouard@174
   498
    *ctext = NULL;
Edouard@174
   499
    *csize = 0;
Edouard@174
   500
Edouard@207
   501
    // Get signing details from netpgp
Edouard@252
   502
    if ((userid = netpgp_getvar(&netpgp, "userid")) == NULL || 
Edouard@252
   503
        (keypair = pgp_getkeybyname(netpgp.io, netpgp.secring, userid)) == NULL ||
Edouard@207
   504
        (seckey = pgp_decrypt_seckey(keypair, NULL /*passfp*/)) == NULL) {
Edouard@207
   505
        return PEP_UNKNOWN_ERROR;
Edouard@207
   506
    }
Edouard@209
   507
Edouard@252
   508
    hashalg = netpgp_getvar(&netpgp, "hash");
Edouard@209
   509
    // netpgp (l)imitation - XXX why ? 
Edouard@207
   510
    if (seckey->pubkey.alg == PGP_PKA_DSA) {
Edouard@209
   511
        hashalg = "sha1";
Edouard@207
   512
    }
Edouard@207
   513
Edouard@207
   514
    // Sign data
Edouard@252
   515
    signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
Edouard@209
   516
                time(NULL), /* birthtime */
Edouard@209
   517
                0 /* duration */,
Edouard@209
   518
                hashalg, 
Edouard@207
   519
                0 /* armored */,
Edouard@207
   520
                0 /* cleartext */);
Edouard@207
   521
Edouard@207
   522
    pgp_forget(seckey, (unsigned)sizeof(*seckey));
Edouard@207
   523
Edouard@207
   524
    if (!signedmem) {
Edouard@252
   525
        result = PEP_UNENCRYPTED;
Edouard@252
   526
        goto unlock_netpgp;
Edouard@207
   527
    }
Edouard@207
   528
Edouard@207
   529
    // Encrypt signed data
Edouard@209
   530
    if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
Edouard@209
   531
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   532
        goto free_signedmem;
Edouard@209
   533
    }
Edouard@209
   534
    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
Edouard@174
   535
        assert(_keylist->value);
Edouard@209
   536
        // get key from netpgp's pubring
Edouard@209
   537
        const pgp_key_t *key;
Edouard@252
   538
        key = pgp_getkeybyname(netpgp.io,
Edouard@252
   539
                               netpgp.pubring,
Edouard@209
   540
                               _keylist->value);
Edouard@209
   541
Edouard@209
   542
        if(key == NULL){
Edouard@209
   543
            result = PEP_KEY_NOT_FOUND;
Edouard@209
   544
            goto free_rcpts;
Edouard@209
   545
        }
Edouard@209
   546
Edouard@209
   547
        // add key to recipients/signers
Edouard@209
   548
        pgp_keyring_add(rcpts, key);
Edouard@209
   549
        if(rcpts->keys == NULL){
Edouard@209
   550
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   551
            goto free_signedmem;
Edouard@209
   552
        }
Edouard@174
   553
    }
Edouard@174
   554
Edouard@252
   555
    cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
Edouard@209
   556
            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
Edouard@252
   557
            netpgp_getvar(&netpgp, "cipher"), 
Edouard@209
   558
            1 /* takes raw OpenPGP message */);
Edouard@209
   559
Edouard@209
   560
    if (cmem == NULL) {
Edouard@209
   561
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   562
        goto free_signedmem;
Edouard@209
   563
    }else{
Edouard@209
   564
Edouard@209
   565
        char *_buffer = NULL;
Edouard@209
   566
        size_t length = pgp_mem_len(cmem);
Edouard@174
   567
Edouard@209
   568
        // Allocate transferable buffer
Edouard@209
   569
        _buffer = malloc(length + 1);
Edouard@209
   570
        assert(_buffer);
Edouard@209
   571
        if (_buffer == NULL) {
Edouard@209
   572
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   573
            goto free_cmem;
Edouard@209
   574
        }
Edouard@209
   575
Edouard@209
   576
        memcpy(_buffer, pgp_mem_data(cmem), length);
Edouard@209
   577
Edouard@209
   578
        *ctext = _buffer;
Edouard@209
   579
        *csize = length;
Edouard@209
   580
        (*ctext)[*csize] = 0; // safeguard for naive users
Edouard@209
   581
        result = PEP_STATUS_OK;
Edouard@174
   582
    }
Edouard@174
   583
Edouard@209
   584
free_cmem :
Edouard@209
   585
    pgp_memory_free(cmem);
Edouard@209
   586
free_rcpts :
Edouard@209
   587
    pgp_keyring_free(rcpts);
Edouard@209
   588
free_signedmem :
Edouard@209
   589
    pgp_memory_free(signedmem);
Edouard@252
   590
unlock_netpgp:
Edouard@252
   591
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@175
   592
Edouard@174
   593
    return result;
Edouard@174
   594
}
Edouard@174
   595
Edouard@227
   596
/* return the hexdump as a string */
Edouard@227
   597
static unsigned
Edouard@227
   598
fpr_to_str (char **str, const uint8_t *fpr, size_t length)
Edouard@227
   599
{
Edouard@228
   600
    unsigned i;
Edouard@228
   601
    int	n;
Edouard@227
   602
Edouard@227
   603
    /* 5 char per byte (hexes + space) tuple -1 space at the end + null */
Edouard@227
   604
    *str = malloc((length / 2) * 5 - 1 + 1);
Edouard@227
   605
Edouard@227
   606
    if(*str == NULL)
Edouard@227
   607
        return 0;
Edouard@227
   608
Edouard@243
   609
    for (n = 0, i = 0 ; i < length - 2; i += 2) {
Edouard@243
   610
    	n += snprintf(&((*str)[n]), 6, "%02x%02x ", fpr[i], fpr[i+1]);
Edouard@228
   611
    }
Edouard@243
   612
    snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
Edouard@227
   613
Edouard@228
   614
    return 1;
Edouard@227
   615
}
Edouard@227
   616
Edouard@227
   617
static unsigned
Edouard@227
   618
str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
Edouard@227
   619
{
Edouard@227
   620
    unsigned i,j;
Edouard@227
   621
Edouard@227
   622
    *length = 0;
Edouard@227
   623
Edouard@227
   624
    while(*str && *length < PGP_FINGERPRINT_SIZE){
Edouard@227
   625
        while (*str == ' ') str++;
Edouard@227
   626
        for (j = 0; j < 2; j++) {
Edouard@227
   627
            uint8_t *byte = &fpr[*length];
Edouard@243
   628
            *byte = 0;
Edouard@227
   629
            for (i = 0; i < 2; i++) {
Edouard@227
   630
                if (i > 0)
Edouard@243
   631
                    *byte = *byte << 4;
Edouard@227
   632
                if (*str >= 'a' && *str <= 'f')
Edouard@227
   633
                    *byte += 10 + *str - 'a';
Edouard@227
   634
                else if (*str >= 'A' && *str <= 'F')
Edouard@227
   635
                    *byte += 10 + *str - 'A';
Edouard@227
   636
                else if (*str >= '0' && *str <= '9')
Edouard@227
   637
                    *byte += *str - '0';
Edouard@227
   638
                else 
Edouard@227
   639
                    return 0;
Edouard@227
   640
                str++;
Edouard@227
   641
            }
Edouard@243
   642
            (*length)++;
Edouard@227
   643
        }
Edouard@227
   644
    }
Edouard@227
   645
    return 1;
Edouard@227
   646
}
Edouard@227
   647
Edouard@228
   648
static PEP_STATUS import_key_or_keypair(netpgp_t *netpgp, pgp_key_t *newkey){
Edouard@228
   649
    pgp_key_t	pubkey;
Edouard@228
   650
    unsigned public;
Edouard@228
   651
    PEP_STATUS result;
Edouard@243
   652
    
Edouard@271
   653
    /* XXX TODO : check key is valid */
Edouard@271
   654
    /* XXX TODO : replace/update key if already in ring */
Edouard@271
   655
Edouard@228
   656
    if ((public = (newkey->type == PGP_PTAG_CT_PUBLIC_KEY))){
Edouard@228
   657
        pubkey = *newkey;
Edouard@228
   658
    } else {
Edouard@228
   659
        // Duplicate key as public only
Edouard@243
   660
        bzero(&pubkey, sizeof(pubkey));
Edouard@228
   661
        if (!pgp_keydata_dup(&pubkey, newkey, 1 /* make_public */)){
Edouard@228
   662
            return PEP_OUT_OF_MEMORY;
Edouard@228
   663
        }
Edouard@228
   664
    }
Edouard@228
   665
Edouard@252
   666
    // Append key to netpgp's rings (key ownership transfered)
Edouard@228
   667
    if (!public && !pgp_keyring_add(netpgp->secring, newkey)){
Edouard@228
   668
        result = PEP_OUT_OF_MEMORY;
Edouard@228
   669
        goto free_pubkey;
Edouard@228
   670
    } else if (!pgp_keyring_add(netpgp->pubring, &pubkey)){
Edouard@228
   671
        result = PEP_OUT_OF_MEMORY;
Edouard@228
   672
        goto pop_secring;
Edouard@228
   673
    }
Edouard@228
   674
Edouard@228
   675
    // save rings 
Edouard@228
   676
    if (netpgp_save_pubring(netpgp) && 
Edouard@228
   677
        (!public || netpgp_save_secring(netpgp)))
Edouard@228
   678
    {
Edouard@228
   679
        /* free nothing, everything transfered */
Edouard@228
   680
        return PEP_STATUS_OK;
Edouard@228
   681
    } else {
Edouard@228
   682
        /* XXX in case only pubring save succeed
Edouard@228
   683
         * pubring file is left as-is, but backup restore
Edouard@228
   684
         * could be attempted if such corner case matters */
Edouard@228
   685
        result = PEP_UNKNOWN_ERROR;
Edouard@228
   686
    }
Edouard@228
   687
Edouard@228
   688
pop_pubring:
Edouard@228
   689
    ((pgp_keyring_t *)netpgp->pubring)->keyc--;
Edouard@228
   690
pop_secring:
Edouard@228
   691
    ((pgp_keyring_t *)netpgp->secring)->keyc--;
Edouard@228
   692
free_pubkey:
Edouard@228
   693
    pgp_key_free(&pubkey);
Edouard@228
   694
Edouard@228
   695
    return result;
Edouard@228
   696
}
Edouard@228
   697
Edouard@174
   698
PEP_STATUS pgp_generate_keypair(
Edouard@174
   699
    PEP_SESSION session, pEp_identity *identity
Edouard@174
   700
    )
Edouard@174
   701
{
Edouard@228
   702
    pgp_key_t	newkey;
Edouard@225
   703
Edouard@225
   704
    PEP_STATUS result;
Edouard@228
   705
    char newid[1024];
Edouard@225
   706
    const char *hashalg;
Edouard@225
   707
    const char *cipher;
Edouard@174
   708
Edouard@174
   709
    assert(session);
Edouard@174
   710
    assert(identity);
Edouard@174
   711
    assert(identity->address);
Edouard@174
   712
    assert(identity->fpr == NULL);
Edouard@174
   713
    assert(identity->username);
Edouard@174
   714
Edouard@225
   715
    if(!session || !identity || 
Edouard@225
   716
       !identity->address || identity->fpr || !identity->username)
Edouard@225
   717
        return PEP_UNKNOWN_ERROR;
Edouard@174
   718
Edouard@263
   719
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   720
        return PEP_UNKNOWN_ERROR;
Edouard@252
   721
    }
Edouard@225
   722
Edouard@225
   723
    if(snprintf(newid, sizeof(newid),
Edouard@225
   724
        "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
Edouard@252
   725
        result =  PEP_BUFFER_TOO_SMALL;
Edouard@252
   726
        goto unlock_netpgp;
Edouard@174
   727
    }
Edouard@225
   728
    
Edouard@252
   729
    hashalg = netpgp_getvar(&netpgp, "hash");
Edouard@252
   730
    cipher = netpgp_getvar(&netpgp, "cipher");
Edouard@174
   731
Edouard@225
   732
    bzero(&newkey, sizeof(newkey));
Edouard@174
   733
Edouard@225
   734
    // Generate the key
Edouard@225
   735
    if (!pgp_rsa_generate_keypair(&newkey, 4096, 65537UL, hashalg, cipher,
Edouard@225
   736
                                  (const uint8_t *) "", (const size_t) 0) ||
Edouard@228
   737
        !pgp_add_selfsigned_userid(&newkey, (uint8_t *)newid)) {
Edouard@228
   738
        result = PEP_CANNOT_CREATE_KEY;
Edouard@228
   739
        goto free_newkey;
Edouard@228
   740
    }
Edouard@225
   741
Edouard@225
   742
    // TODO "Expire-Date: 1y\n";
Edouard@225
   743
Edouard@174
   744
Edouard@252
   745
    result = import_key_or_keypair(&netpgp, &newkey);
Edouard@225
   746
Edouard@228
   747
    if (result == PEP_STATUS_OK) {
Edouard@254
   748
        char *fprstr = NULL;
Edouard@254
   749
        fpr_to_str(&fprstr,
Edouard@254
   750
                   newkey.sigfingerprint.fingerprint,
Edouard@254
   751
                   newkey.sigfingerprint.length);
Edouard@254
   752
        if (fprstr == NULL) {
Edouard@254
   753
            result = PEP_OUT_OF_MEMORY;
Edouard@254
   754
            goto free_newkey;
Edouard@254
   755
        } 
Edouard@228
   756
        identity->fpr = fprstr;
Edouard@228
   757
        /* free nothing, everything transfered */
Edouard@252
   758
        result = PEP_STATUS_OK;
Edouard@252
   759
        goto unlock_netpgp;
Edouard@225
   760
    }
Edouard@174
   761
Edouard@228
   762
free_newkey:
Edouard@228
   763
    pgp_key_free(&newkey);
Edouard@252
   764
unlock_netpgp:
Edouard@252
   765
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
   766
Edouard@225
   767
    return result;
Edouard@174
   768
}
Edouard@174
   769
Edouard@227
   770
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
Edouard@174
   771
{
Edouard@227
   772
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@227
   773
    size_t length;
Edouard@227
   774
Edouard@227
   775
    PEP_STATUS result;
Edouard@227
   776
Edouard@174
   777
    assert(session);
Edouard@174
   778
    assert(fpr);
Edouard@174
   779
Edouard@227
   780
    if (!session || !fpr)
Edouard@174
   781
        return PEP_UNKNOWN_ERROR;
Edouard@174
   782
Edouard@263
   783
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   784
        return PEP_UNKNOWN_ERROR;
Edouard@252
   785
    }
Edouard@227
   786
    
Edouard@227
   787
    if (str_to_fpr(fprstr, fpr, &length)) {
Edouard@252
   788
        unsigned insec = pgp_deletekeybyfpr(netpgp.io,
Edouard@252
   789
                                (pgp_keyring_t *)netpgp.secring, 
Edouard@244
   790
                                (const uint8_t *)fpr, length);
Edouard@252
   791
        unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
Edouard@252
   792
                                (pgp_keyring_t *)netpgp.pubring, 
Edouard@244
   793
                                (const uint8_t *)fpr, length);
Edouard@244
   794
        if(!insec && !inpub){
Edouard@244
   795
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   796
            goto unlock_netpgp;
Edouard@244
   797
        } else {
Edouard@244
   798
            result = PEP_STATUS_OK;
Edouard@227
   799
        }
Edouard@227
   800
    }else{
Edouard@252
   801
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   802
        goto unlock_netpgp;
Edouard@227
   803
    }
Edouard@174
   804
Edouard@227
   805
    // save rings (key ownership transfered)
Edouard@252
   806
    if (netpgp_save_pubring(&netpgp) && 
Edouard@252
   807
        netpgp_save_secring(&netpgp))
Edouard@227
   808
    {
Edouard@227
   809
        result = PEP_STATUS_OK;
Edouard@227
   810
    }else{
Edouard@227
   811
        result = PEP_UNKNOWN_ERROR;
Edouard@227
   812
    }
Edouard@227
   813
Edouard@252
   814
unlock_netpgp:
Edouard@252
   815
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   816
Edouard@227
   817
    return result;
Edouard@174
   818
}
Edouard@174
   819
Edouard@228
   820
#define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----\\s*$"
Edouard@179
   821
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data, size_t size)
Edouard@174
   822
{
Edouard@228
   823
Edouard@228
   824
    pgp_memory_t *mem;
Edouard@228
   825
    pgp_keyring_t tmpring;
Edouard@271
   826
    unsigned i = 0;
Edouard@228
   827
Edouard@271
   828
    PEP_STATUS result = PEP_STATUS_OK;
Edouard@228
   829
Edouard@174
   830
    assert(session);
Edouard@174
   831
    assert(key_data);
Edouard@174
   832
Edouard@228
   833
    if(!session || !key_data) 
Edouard@174
   834
        return PEP_UNKNOWN_ERROR;
Edouard@228
   835
Edouard@263
   836
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   837
        return PEP_UNKNOWN_ERROR;
Edouard@252
   838
    }
Edouard@228
   839
Edouard@228
   840
    mem = pgp_memory_new();
Edouard@228
   841
    if (mem == NULL) {
Edouard@252
   842
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   843
        goto unlock_netpgp;
Edouard@228
   844
    }
Edouard@228
   845
    pgp_memory_add(mem, (const uint8_t*)key_data, size);
Edouard@228
   846
Edouard@244
   847
    bzero(&tmpring, sizeof(tmpring));
Edouard@244
   848
Edouard@252
   849
    if (pgp_keyring_read_from_mem(netpgp.io, &tmpring, 
Edouard@228
   850
                                  _armoured(key_data, size, ARMOR_KEY_HEAD),
Edouard@228
   851
                                  mem) == 0){
Edouard@228
   852
        result = PEP_ILLEGAL_VALUE;
Edouard@228
   853
    }else if (tmpring.keyc == 0){
Edouard@228
   854
        result = PEP_UNKNOWN_ERROR;
Edouard@271
   855
    }else while(result == PEP_STATUS_OK && i < tmpring.keyc){
Edouard@271
   856
        result = import_key_or_keypair(&netpgp, &tmpring.keys[i++]);
Edouard@228
   857
    }
Edouard@228
   858
    
Edouard@228
   859
    pgp_memory_free(mem);
Edouard@228
   860
Edouard@244
   861
    if (result == PEP_STATUS_OK){
Edouard@244
   862
        pgp_keyring_free(&tmpring);
Edouard@244
   863
    }else{
Edouard@228
   864
        pgp_keyring_purge(&tmpring);
Edouard@228
   865
    }
Edouard@228
   866
Edouard@252
   867
unlock_netpgp:
Edouard@252
   868
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   869
Edouard@228
   870
    return result;
Edouard@174
   871
}
Edouard@174
   872
Edouard@179
   873
PEP_STATUS pgp_export_keydata(
Edouard@228
   874
    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
Edouard@174
   875
    )
Edouard@174
   876
{
Edouard@228
   877
    pgp_key_t *key;
Edouard@228
   878
	pgp_output_t *output;
Edouard@228
   879
    pgp_memory_t *mem;
Edouard@228
   880
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@228
   881
    size_t fprlen;
Edouard@228
   882
Edouard@228
   883
    PEP_STATUS result;
Edouard@174
   884
    char *buffer;
Edouard@228
   885
    size_t buflen;
Edouard@174
   886
Edouard@174
   887
    assert(session);
Edouard@243
   888
    assert(fprstr);
Edouard@174
   889
    assert(key_data);
Edouard@174
   890
    assert(size);
Edouard@174
   891
Edouard@243
   892
    if (!session || !fprstr || !key_data || !size)
Edouard@174
   893
        return PEP_UNKNOWN_ERROR;
Edouard@174
   894
Edouard@263
   895
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   896
        return PEP_UNKNOWN_ERROR;
Edouard@252
   897
    }
Edouard@252
   898
Edouard@228
   899
    if (str_to_fpr(fprstr, fpr, &fprlen)) {
Edouard@252
   900
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring, 
Edouard@228
   901
                                                fpr, fprlen,
Edouard@254
   902
                                                NULL)) == NULL) {
Edouard@252
   903
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   904
            goto unlock_netpgp;
Edouard@228
   905
        }
Edouard@228
   906
    }else{
Edouard@252
   907
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   908
        goto unlock_netpgp;
Edouard@228
   909
    }
Edouard@228
   910
    
Edouard@228
   911
	pgp_setup_memory_write(&output, &mem, 128);
Edouard@174
   912
Edouard@228
   913
    if (mem == NULL || output == NULL) {
Edouard@252
   914
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   915
        goto unlock_netpgp;
Edouard@174
   916
    }
Edouard@174
   917
Edouard@228
   918
    if (!pgp_write_xfer_pubkey(output, key, 1)) {
Edouard@228
   919
        result = PEP_UNKNOWN_ERROR;
Edouard@228
   920
        goto free_mem;
Edouard@228
   921
    }
Edouard@228
   922
Edouard@228
   923
    buffer = NULL;
Edouard@228
   924
    buflen = pgp_mem_len(mem);
Edouard@228
   925
Edouard@228
   926
    // Allocate transferable buffer
Edouard@228
   927
    buffer = malloc(buflen + 1);
Edouard@228
   928
    assert(buffer);
Edouard@228
   929
    if (buffer == NULL) {
Edouard@228
   930
        result = PEP_OUT_OF_MEMORY;
Edouard@228
   931
        goto free_mem;
Edouard@228
   932
    }
Edouard@228
   933
Edouard@228
   934
    memcpy(buffer, pgp_mem_data(mem), buflen);
Edouard@174
   935
Edouard@174
   936
    *key_data = buffer;
Edouard@228
   937
    *size = buflen;
Edouard@228
   938
    (*key_data)[*size] = 0; // safeguard for naive users
Edouard@228
   939
    result = PEP_STATUS_OK;
Edouard@174
   940
Edouard@228
   941
free_mem :
Edouard@228
   942
	pgp_teardown_memory_write(output, mem);
Edouard@252
   943
unlock_netpgp:
Edouard@252
   944
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
   945
Edouard@228
   946
    return result;
Edouard@174
   947
}
Edouard@174
   948
Edouard@271
   949
struct HKP_answer {
Edouard@271
   950
  char *memory;
Edouard@271
   951
  size_t size;
Edouard@271
   952
};
Edouard@271
   953
 
Edouard@271
   954
static size_t
Edouard@271
   955
HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
Edouard@271
   956
{
Edouard@271
   957
  size_t realsize = size * nmemb;
Edouard@271
   958
  struct HKP_answer *mem = (struct HKP_answer *)userp;
Edouard@271
   959
 
Edouard@271
   960
  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
Edouard@271
   961
  if(mem->memory == NULL) {
Edouard@271
   962
    mem->size = 0;
Edouard@271
   963
    return 0;
Edouard@271
   964
  }
Edouard@271
   965
 
Edouard@271
   966
  memcpy(&(mem->memory[mem->size]), contents, realsize);
Edouard@271
   967
  mem->size += realsize;
Edouard@271
   968
  mem->memory[mem->size] = 0;
Edouard@271
   969
 
Edouard@271
   970
  return realsize;
Edouard@271
   971
}
Edouard@271
   972
Edouard@174
   973
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
Edouard@174
   974
{
Edouard@271
   975
    static const char *ks_cmd = "http://keys.gnupg.net:11371/pks/lookup?"
Edouard@271
   976
                                "op=get&options=mr&exact=on&"
Edouard@271
   977
                                "search=";
Edouard@271
   978
    char *encoded_pattern;
Edouard@271
   979
    char *request = NULL;
Edouard@271
   980
    struct HKP_answer answer;
Edouard@271
   981
    CURLcode curlres;
Edouard@271
   982
       
Edouard@271
   983
    PEP_STATUS result;
Edouard@271
   984
Edouard@271
   985
    CURL *curl;
Edouard@271
   986
Edouard@174
   987
    assert(session);
Edouard@174
   988
    assert(pattern);
Edouard@174
   989
Edouard@271
   990
    if (!session || !pattern )
Edouard@271
   991
        return PEP_UNKNOWN_ERROR;
Edouard@271
   992
Edouard@271
   993
    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
Edouard@271
   994
        return PEP_UNKNOWN_ERROR;
Edouard@271
   995
    }
Edouard@271
   996
Edouard@252
   997
    curl = session->ctx.curl;
Edouard@252
   998
Edouard@271
   999
    encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
Edouard@271
  1000
    if(!encoded_pattern){
Edouard@271
  1001
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1002
        goto unlock_curl;
Edouard@271
  1003
    }
Edouard@271
  1004
Edouard@271
  1005
    if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
Edouard@271
  1006
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1007
        goto free_encoded_pattern;
Edouard@271
  1008
    }
Edouard@174
  1009
Edouard@271
  1010
    //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
Edouard@271
  1011
    stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
Edouard@271
  1012
Edouard@271
  1013
    curl_easy_setopt(curl, CURLOPT_URL,request);
Edouard@271
  1014
Edouard@271
  1015
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
Edouard@271
  1016
Edouard@271
  1017
    answer.memory = NULL;
Edouard@271
  1018
    answer.size = 0;
Edouard@271
  1019
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
Edouard@174
  1020
Edouard@271
  1021
    curlres = curl_easy_perform(curl);
Edouard@271
  1022
    if(curlres != CURLE_OK) {
Edouard@271
  1023
        result = PEP_GET_KEY_FAILED;
Edouard@271
  1024
        goto free_request;
Edouard@271
  1025
    }
Edouard@271
  1026
Edouard@271
  1027
    if(!answer.memory || !answer.size) {
Edouard@271
  1028
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1029
        goto free_request;
Edouard@271
  1030
    }
Edouard@174
  1031
Edouard@271
  1032
    result = pgp_import_keydata(session, 
Edouard@271
  1033
                                answer.memory, 
Edouard@271
  1034
                                answer.size);
Edouard@271
  1035
Edouard@271
  1036
free_answer:
Edouard@271
  1037
    free(answer.memory);
Edouard@271
  1038
free_request:
Edouard@271
  1039
    free(request);
Edouard@271
  1040
free_encoded_pattern:
Edouard@271
  1041
    curl_free(encoded_pattern);
Edouard@271
  1042
unlock_curl:
Edouard@271
  1043
    pthread_mutex_unlock(&session->ctx.curl_mutex);
Edouard@271
  1044
Edouard@271
  1045
    return result;
Edouard@174
  1046
}
Edouard@174
  1047
Edouard@277
  1048
typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
Edouard@277
  1049
Edouard@277
  1050
static PEP_STATUS find_keys_do(
Edouard@277
  1051
        const char *pattern, find_key_cb_t cb, void* cb_arg)
Edouard@254
  1052
{
Edouard@277
  1053
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@277
  1054
    size_t length;
Edouard@277
  1055
    pgp_key_t *key;
Edouard@277
  1056
Edouard@277
  1057
    PEP_STATUS result;
Edouard@277
  1058
Edouard@277
  1059
    // Try find a fingerprint in pattern
Edouard@277
  1060
    if (str_to_fpr(pattern, fpr, &length)) {
Edouard@277
  1061
Edouard@277
  1062
        // Only one fingerprint can match
Edouard@277
  1063
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(
Edouard@277
  1064
                        netpgp.io,
Edouard@277
  1065
                        (pgp_keyring_t *)netpgp.pubring, 
Edouard@277
  1066
                        (const uint8_t *)fpr, length,
Edouard@277
  1067
                        NULL)) == NULL) {
Edouard@277
  1068
Edouard@277
  1069
            return PEP_KEY_NOT_FOUND;
Edouard@277
  1070
        }
Edouard@277
  1071
Edouard@277
  1072
        result = cb(cb_arg, key);
Edouard@277
  1073
Edouard@277
  1074
    } else {
Edouard@277
  1075
        // Search by name for pattern. Can match many.
Edouard@277
  1076
        unsigned from = 0;
Edouard@277
  1077
        result = PEP_KEY_NOT_FOUND;
Edouard@277
  1078
        while((key = (pgp_key_t *)pgp_getnextkeybyname(
Edouard@277
  1079
                        netpgp.io,
Edouard@277
  1080
                        (pgp_keyring_t *)netpgp.pubring, 
Edouard@277
  1081
			            (const char *)pattern,
Edouard@277
  1082
                        &from)) != NULL) {
Edouard@277
  1083
Edouard@277
  1084
            result = cb(cb_arg, key);
Edouard@277
  1085
            if (result != PEP_STATUS_OK)
Edouard@277
  1086
                break;
Edouard@277
  1087
Edouard@277
  1088
            from++;
Edouard@277
  1089
        }
Edouard@277
  1090
    }
Edouard@277
  1091
Edouard@277
  1092
    return result;
Edouard@277
  1093
}
Edouard@277
  1094
Edouard@277
  1095
static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
Edouard@277
  1096
{
Edouard@277
  1097
    stringlist_t **keylist = arg;
Edouard@254
  1098
    char *newfprstr = NULL;
Edouard@254
  1099
Edouard@254
  1100
    fpr_to_str(&newfprstr,
Edouard@254
  1101
               key->sigfingerprint.fingerprint,
Edouard@254
  1102
               key->sigfingerprint.length);
Edouard@254
  1103
Edouard@254
  1104
    if (newfprstr == NULL) {
Edouard@254
  1105
        return PEP_OUT_OF_MEMORY;
Edouard@254
  1106
    } else { 
Edouard@254
  1107
Edouard@254
  1108
        *keylist = stringlist_add(*keylist, newfprstr);
Edouard@254
  1109
        if (*keylist == NULL) {
Edouard@254
  1110
            free(newfprstr);
Edouard@254
  1111
            return PEP_OUT_OF_MEMORY;
Edouard@254
  1112
        }
Edouard@254
  1113
    }
Edouard@254
  1114
    return PEP_STATUS_OK;
Edouard@254
  1115
}
Edouard@254
  1116
Edouard@174
  1117
PEP_STATUS pgp_find_keys(
Edouard@174
  1118
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
Edouard@174
  1119
    )
Edouard@174
  1120
{
Edouard@254
  1121
    stringlist_t *_keylist, *_k;
Edouard@254
  1122
Edouard@254
  1123
    PEP_STATUS result;
Edouard@174
  1124
Edouard@174
  1125
    assert(session);
Edouard@174
  1126
    assert(pattern);
Edouard@174
  1127
    assert(keylist);
Edouard@174
  1128
Edouard@254
  1129
    if (!session || !pattern || !keylist )
Edouard@254
  1130
        return PEP_UNKNOWN_ERROR;
Edouard@174
  1131
Edouard@263
  1132
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@174
  1133
        return PEP_UNKNOWN_ERROR;
Edouard@254
  1134
    }
Edouard@254
  1135
Edouard@254
  1136
    *keylist = NULL;
Edouard@254
  1137
    _keylist = new_stringlist(NULL);
Edouard@254
  1138
    if (_k == NULL) {
Edouard@254
  1139
        result = PEP_OUT_OF_MEMORY;
Edouard@254
  1140
        goto unlock_netpgp;
Edouard@254
  1141
    }
Edouard@254
  1142
    _k = _keylist;
Edouard@254
  1143
Edouard@277
  1144
    result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
Edouard@254
  1145
Edouard@254
  1146
    if (result == PEP_STATUS_OK) {
Edouard@254
  1147
        *keylist = _keylist;
Edouard@254
  1148
        // Transfer ownership, no free
Edouard@254
  1149
        goto unlock_netpgp;
Edouard@254
  1150
    }
Edouard@254
  1151
Edouard@254
  1152
free_keylist:
Edouard@254
  1153
    free_stringlist(_keylist);
Edouard@254
  1154
Edouard@254
  1155
unlock_netpgp:
Edouard@254
  1156
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@254
  1157
Edouard@254
  1158
    return result;
Edouard@174
  1159
}
Edouard@174
  1160
Edouard@277
  1161
static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
Edouard@277
  1162
{
Edouard@277
  1163
    char *newfprstr = NULL;
Edouard@277
  1164
Edouard@277
  1165
    fpr_to_str(&newfprstr,
Edouard@277
  1166
               key->sigfingerprint.fingerprint,
Edouard@277
  1167
               key->sigfingerprint.length);
Edouard@277
  1168
Edouard@277
  1169
    if (newfprstr == NULL) {
Edouard@277
  1170
        return PEP_OUT_OF_MEMORY;
Edouard@277
  1171
    } else { 
Edouard@277
  1172
Edouard@277
  1173
        printf("would send:\n%s\n", newfprstr);
Edouard@277
  1174
        pgp_print_keydata(netpgp.io, netpgp.pubring, key, "to send", &key->key.pubkey, 0);
Edouard@277
  1175
        free(newfprstr);
Edouard@277
  1176
    }
Edouard@277
  1177
    return PEP_STATUS_OK;
Edouard@277
  1178
}
Edouard@277
  1179
Edouard@174
  1180
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
Edouard@174
  1181
{
Edouard@277
  1182
Edouard@277
  1183
    PEP_STATUS result;
Edouard@277
  1184
Edouard@174
  1185
    assert(session);
Edouard@174
  1186
    assert(pattern);
Edouard@174
  1187
Edouard@277
  1188
    if (!session || !pattern )
Edouard@277
  1189
        return PEP_UNKNOWN_ERROR;
Edouard@277
  1190
Edouard@277
  1191
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@277
  1192
        return PEP_UNKNOWN_ERROR;
Edouard@277
  1193
    }
Edouard@174
  1194
Edouard@277
  1195
    result = find_keys_do(pattern, &send_key_cb, NULL);
Edouard@277
  1196
Edouard@277
  1197
    result = PEP_CANNOT_SEND_KEY;
Edouard@277
  1198
unlock_netpgp:
Edouard@277
  1199
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@277
  1200
Edouard@277
  1201
    return result;
Edouard@174
  1202
}
Edouard@174
  1203
Edouard@174
  1204
Edouard@174
  1205
PEP_STATUS pgp_get_key_rating(
Edouard@174
  1206
    PEP_SESSION session,
Edouard@174
  1207
    const char *fpr,
Edouard@174
  1208
    PEP_comm_type *comm_type
Edouard@174
  1209
    )
Edouard@174
  1210
{
Edouard@174
  1211
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@174
  1212
Edouard@174
  1213
    assert(session);
Edouard@174
  1214
    assert(fpr);
Edouard@174
  1215
    assert(comm_type);
Edouard@174
  1216
Edouard@174
  1217
    *comm_type = PEP_ct_unknown;
Edouard@174
  1218
Edouard@174
  1219
    /* TODO get key from fpr */
Edouard@174
  1220
    return PEP_UNKNOWN_ERROR;
Edouard@174
  1221
    return PEP_GET_KEY_FAILED;
Edouard@174
  1222
Edouard@174
  1223
    switch (/*TODO key->protocol*/ 4) {
Edouard@174
  1224
    case /* TODO  OpenPGP */0:
Edouard@174
  1225
    case /* TODO DEFAULT */1:
Edouard@174
  1226
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
Edouard@174
  1227
        break;
Edouard@174
  1228
    case /* TODO CMS */2:
Edouard@174
  1229
        *comm_type = PEP_ct_CMS_unconfirmed;
Edouard@174
  1230
        break;
Edouard@174
  1231
    default:
Edouard@174
  1232
        *comm_type = PEP_ct_unknown;
Edouard@174
  1233
        return PEP_STATUS_OK;
Edouard@174
  1234
    }
Edouard@174
  1235
Edouard@174
  1236
        for (; 1 == 0; /* Each subkeys */ ) {
Edouard@174
  1237
            if (/* TODO length */0 < 1024)
Edouard@174
  1238
                *comm_type = PEP_ct_key_too_short;
Edouard@174
  1239
            else if (
Edouard@174
  1240
                (
Edouard@174
  1241
                (   /* TODO pubkey_algo == RSA  */ 0)
Edouard@174
  1242
                || (/* TODO pubkey_algo == RSA_E*/ 0)
Edouard@174
  1243
                || (/* TODO pubkey_algo == RSA_S*/ 0)
Edouard@174
  1244
                )
Edouard@174
  1245
                && /* sk->length */0 == 1024
Edouard@174
  1246
                )
Edouard@174
  1247
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
Edouard@174
  1248
Edouard@174
  1249
            if (/* TODO invalid */ 1) {
Edouard@174
  1250
                *comm_type = PEP_ct_key_b0rken;
Edouard@174
  1251
                break;
Edouard@174
  1252
            }
Edouard@174
  1253
            if (/* TODO expired */ 1) {
Edouard@174
  1254
                *comm_type = PEP_ct_key_expired;
Edouard@174
  1255
                break;
Edouard@174
  1256
            }
Edouard@175
  1257
            if (/* TODO revoked*/ 1) {
Edouard@174
  1258
                *comm_type = PEP_ct_key_revoked;
Edouard@174
  1259
                break;
Edouard@174
  1260
            }
Edouard@174
  1261
        }
Edouard@174
  1262
        *comm_type = PEP_ct_unknown;
Edouard@174
  1263
        return PEP_OUT_OF_MEMORY;
Edouard@174
  1264
        return PEP_UNKNOWN_ERROR;
Edouard@174
  1265
Edouard@174
  1266
Edouard@174
  1267
    return status;
Edouard@174
  1268
}
Edouard@210
  1269
Edouard@210
  1270
PEP_STATUS pgp_renew_key(
Edouard@210
  1271
        PEP_SESSION session,
Edouard@210
  1272
        const char *fpr,
Edouard@210
  1273
        const timestamp *ts
Edouard@210
  1274
    )
Edouard@210
  1275
{
Edouard@210
  1276
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
  1277
    char date_text[12];
Edouard@210
  1278
Edouard@210
  1279
    assert(session);
Edouard@210
  1280
    assert(fpr);
Edouard@210
  1281
Edouard@210
  1282
    snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
Edouard@210
  1283
            ts->tm_mon + 1, ts->tm_mday);
Edouard@210
  1284
Edouard@210
  1285
Edouard@210
  1286
        return PEP_UNKNOWN_ERROR;
Edouard@210
  1287
    return PEP_STATUS_OK;
Edouard@210
  1288
}
Edouard@210
  1289
Edouard@226
  1290
PEP_STATUS pgp_revoke_key(
Edouard@226
  1291
        PEP_SESSION session,
Edouard@226
  1292
        const char *fpr,
Edouard@226
  1293
        const char *reason
Edouard@226
  1294
    )
Edouard@210
  1295
{
Edouard@210
  1296
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
  1297
    
Edouard@210
  1298
    assert(session);
Edouard@210
  1299
    assert(fpr);
Edouard@210
  1300
Edouard@210
  1301
        return PEP_UNKNOWN_ERROR;
Edouard@210
  1302
Edouard@210
  1303
    return PEP_STATUS_OK;
Edouard@210
  1304
}
Edouard@210
  1305
Edouard@226
  1306
PEP_STATUS pgp_key_expired(
Edouard@226
  1307
        PEP_SESSION session,
Edouard@226
  1308
        const char *fpr,
Edouard@226
  1309
        bool *expired
Edouard@226
  1310
    )
Edouard@226
  1311
{
Edouard@226
  1312
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@226
  1313
Edouard@226
  1314
    assert(session);
Edouard@226
  1315
    assert(fpr);
Edouard@226
  1316
    assert(expired);
Edouard@226
  1317
Edouard@226
  1318
    *expired = false;
Edouard@226
  1319
Edouard@226
  1320
    if (status != PEP_STATUS_OK)
Edouard@226
  1321
        return status;
Edouard@226
  1322
Edouard@226
  1323
    return PEP_STATUS_OK;
Edouard@226
  1324
}
Edouard@226
  1325