src/pgp_netpgp.c
author Edouard Tisserant
Tue, 12 May 2015 16:13:44 +0200
changeset 271 18b5097c4428
parent 270 22984733d7a6
child 272 f82971ed62e5
permissions -rw-r--r--
netpgp : pgp_recv_key
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@182
   328
        if ((_ptext = calloc(1, _psize)) == 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@182
   333
        result = PEP_DECRYPTED;
Edouard@182
   334
    }else{
Edouard@183
   335
        result = PEP_DECRYPT_NO_KEY;
Edouard@183
   336
        goto free_pgp;
Edouard@182
   337
    }
Edouard@180
   338
Edouard@185
   339
    if (result == PEP_DECRYPTED) {
Edouard@252
   340
        result = _validation_results(&netpgp, vresult, &_keylist);
Edouard@185
   341
        if (result != PEP_STATUS_OK) {
Edouard@185
   342
            goto free_ptext;
Edouard@183
   343
        }
Edouard@180
   344
        result = PEP_DECRYPTED_AND_VERIFIED;
Edouard@180
   345
    }
Edouard@174
   346
Edouard@180
   347
    if (result == PEP_DECRYPTED_AND_VERIFIED
Edouard@180
   348
        || result == PEP_DECRYPTED) {
Edouard@180
   349
        *ptext = _ptext;
Edouard@180
   350
        *psize = _psize;
Edouard@180
   351
        (*ptext)[*psize] = 0; // safeguard for naive users
Edouard@185
   352
        if (result == PEP_DECRYPTED_AND_VERIFIED) {
Edouard@185
   353
            *keylist = _keylist;
Edouard@185
   354
        }
Edouard@183
   355
Edouard@183
   356
        /* _ptext and _keylist ownership transfer, don't free */
Edouard@183
   357
        goto free_pgp;
Edouard@180
   358
    }
Edouard@183
   359
Edouard@183
   360
free_keylist:
Edouard@183
   361
    free_stringlist(_keylist);
Edouard@183
   362
Edouard@183
   363
free_ptext:
Edouard@183
   364
    free(_ptext);
Edouard@183
   365
Edouard@183
   366
free_pgp:
Edouard@185
   367
    pgp_memory_free(mem);
Edouard@183
   368
    pgp_validate_result_free(vresult);
Edouard@183
   369
Edouard@252
   370
unlock_netpgp:
Edouard@252
   371
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   372
Edouard@174
   373
    return result;
Edouard@174
   374
}
Edouard@174
   375
Edouard@207
   376
#define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----\\s*$"
Edouard@174
   377
PEP_STATUS pgp_verify_text(
Edouard@174
   378
    PEP_SESSION session, const char *text, size_t size,
Edouard@174
   379
    const char *signature, size_t sig_size, stringlist_t **keylist
Edouard@174
   380
    )
Edouard@174
   381
{
Edouard@185
   382
    pgp_memory_t *signedmem;
Edouard@185
   383
    pgp_memory_t *sig;
Edouard@185
   384
    pgp_validation_t *vresult;
Edouard@185
   385
Edouard@174
   386
    PEP_STATUS result;
Edouard@174
   387
    stringlist_t *_keylist;
Edouard@174
   388
Edouard@174
   389
    assert(session);
Edouard@174
   390
    assert(text);
Edouard@174
   391
    assert(size);
Edouard@174
   392
    assert(signature);
Edouard@174
   393
    assert(sig_size);
Edouard@174
   394
    assert(keylist);
Edouard@174
   395
Edouard@185
   396
    if(!session || !text || !size || !signature || !sig_size || !keylist) 
Edouard@185
   397
        return PEP_UNKNOWN_ERROR;
Edouard@185
   398
Edouard@263
   399
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   400
        return PEP_UNKNOWN_ERROR;
Edouard@252
   401
    }
Edouard@185
   402
Edouard@174
   403
    *keylist = NULL;
Edouard@185
   404
Edouard@185
   405
    vresult = malloc(sizeof(pgp_validation_t));
Edouard@185
   406
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@185
   407
Edouard@185
   408
    signedmem = pgp_memory_new();
Edouard@185
   409
    if (signedmem == NULL) {
Edouard@252
   410
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   411
        goto unlock_netpgp;
Edouard@185
   412
    }
Edouard@185
   413
    pgp_memory_add(signedmem, (const uint8_t*)text, size);
Edouard@185
   414
Edouard@185
   415
    sig = pgp_memory_new();
Edouard@185
   416
    if (sig == NULL) {
Edouard@185
   417
        pgp_memory_free(signedmem);
Edouard@252
   418
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   419
        goto unlock_netpgp;
Edouard@185
   420
    }
Edouard@185
   421
    pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
Edouard@185
   422
Edouard@252
   423
    pgp_validate_mem_detached(netpgp.io, vresult, sig,
Edouard@185
   424
                NULL,/* output */
Edouard@207
   425
                _armoured(signature, sig_size, ARMOR_SIG_HEAD),
Edouard@252
   426
                netpgp.pubring,
Edouard@185
   427
                signedmem);
Edouard@185
   428
Edouard@252
   429
    result = _validation_results(&netpgp, vresult, &_keylist);
Edouard@185
   430
    if (result != PEP_STATUS_OK) {
Edouard@185
   431
        goto free_pgp;
Edouard@185
   432
    }else{
Edouard@185
   433
        result = PEP_VERIFIED;
Edouard@185
   434
    }
Edouard@185
   435
Edouard@185
   436
    if (result == PEP_VERIFIED) {
Edouard@185
   437
        /* TODO : check trust level */
Edouard@185
   438
        result = PEP_VERIFIED_AND_TRUSTED;
Edouard@185
   439
    }
Edouard@185
   440
Edouard@185
   441
    if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
Edouard@185
   442
        *keylist = _keylist;
Edouard@185
   443
Edouard@185
   444
        /* _keylist ownership transfer, don't free */
Edouard@185
   445
        goto free_pgp;
Edouard@185
   446
    }
Edouard@185
   447
Edouard@185
   448
free_keylist:
Edouard@185
   449
    free_stringlist(_keylist);
Edouard@185
   450
Edouard@185
   451
free_pgp:
Edouard@187
   452
    // free done by pgp_validate_mem_detached
Edouard@187
   453
    // pgp_memory_free(sig);
Edouard@187
   454
    // pgp_memory_free(signedmem);
Edouard@185
   455
    pgp_validate_result_free(vresult);
Edouard@185
   456
Edouard@252
   457
unlock_netpgp:
Edouard@252
   458
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   459
Edouard@185
   460
    return result;
Edouard@174
   461
}
Edouard@174
   462
Edouard@174
   463
PEP_STATUS pgp_encrypt_and_sign(
Edouard@174
   464
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
Edouard@174
   465
    size_t psize, char **ctext, size_t *csize
Edouard@174
   466
    )
Edouard@174
   467
{
Edouard@207
   468
    const pgp_key_t *keypair;
Edouard@207
   469
    pgp_seckey_t *seckey;
Edouard@209
   470
    pgp_memory_t *signedmem;
Edouard@209
   471
    pgp_memory_t *cmem;
Edouard@207
   472
    const char *userid;
Edouard@207
   473
    const char *hashalg;
Edouard@209
   474
    pgp_keyring_t *rcpts;
Edouard@207
   475
Edouard@174
   476
    PEP_STATUS result;
Edouard@174
   477
    const stringlist_t *_keylist;
Edouard@174
   478
Edouard@174
   479
    assert(session);
Edouard@174
   480
    assert(keylist);
Edouard@174
   481
    assert(ptext);
Edouard@174
   482
    assert(psize);
Edouard@174
   483
    assert(ctext);
Edouard@174
   484
    assert(csize);
Edouard@174
   485
Edouard@207
   486
    if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
Edouard@207
   487
        return PEP_UNKNOWN_ERROR;
Edouard@207
   488
Edouard@263
   489
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   490
        return PEP_UNKNOWN_ERROR;
Edouard@252
   491
    }
Edouard@208
   492
Edouard@174
   493
    *ctext = NULL;
Edouard@174
   494
    *csize = 0;
Edouard@174
   495
Edouard@207
   496
    // Get signing details from netpgp
Edouard@252
   497
    if ((userid = netpgp_getvar(&netpgp, "userid")) == NULL || 
Edouard@252
   498
        (keypair = pgp_getkeybyname(netpgp.io, netpgp.secring, userid)) == NULL ||
Edouard@207
   499
        (seckey = pgp_decrypt_seckey(keypair, NULL /*passfp*/)) == NULL) {
Edouard@207
   500
        return PEP_UNKNOWN_ERROR;
Edouard@207
   501
    }
Edouard@209
   502
Edouard@252
   503
    hashalg = netpgp_getvar(&netpgp, "hash");
Edouard@209
   504
    // netpgp (l)imitation - XXX why ? 
Edouard@207
   505
    if (seckey->pubkey.alg == PGP_PKA_DSA) {
Edouard@209
   506
        hashalg = "sha1";
Edouard@207
   507
    }
Edouard@207
   508
Edouard@207
   509
    // Sign data
Edouard@252
   510
    signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
Edouard@209
   511
                time(NULL), /* birthtime */
Edouard@209
   512
                0 /* duration */,
Edouard@209
   513
                hashalg, 
Edouard@207
   514
                0 /* armored */,
Edouard@207
   515
                0 /* cleartext */);
Edouard@207
   516
Edouard@207
   517
    pgp_forget(seckey, (unsigned)sizeof(*seckey));
Edouard@207
   518
Edouard@207
   519
    if (!signedmem) {
Edouard@252
   520
        result = PEP_UNENCRYPTED;
Edouard@252
   521
        goto unlock_netpgp;
Edouard@207
   522
    }
Edouard@207
   523
Edouard@207
   524
    // Encrypt signed data
Edouard@209
   525
    if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
Edouard@209
   526
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   527
        goto free_signedmem;
Edouard@209
   528
    }
Edouard@209
   529
    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
Edouard@174
   530
        assert(_keylist->value);
Edouard@209
   531
        // get key from netpgp's pubring
Edouard@209
   532
        const pgp_key_t *key;
Edouard@252
   533
        key = pgp_getkeybyname(netpgp.io,
Edouard@252
   534
                               netpgp.pubring,
Edouard@209
   535
                               _keylist->value);
Edouard@209
   536
Edouard@209
   537
        if(key == NULL){
Edouard@209
   538
            result = PEP_KEY_NOT_FOUND;
Edouard@209
   539
            goto free_rcpts;
Edouard@209
   540
        }
Edouard@209
   541
Edouard@209
   542
        // add key to recipients/signers
Edouard@209
   543
        pgp_keyring_add(rcpts, key);
Edouard@209
   544
        if(rcpts->keys == NULL){
Edouard@209
   545
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   546
            goto free_signedmem;
Edouard@209
   547
        }
Edouard@174
   548
    }
Edouard@174
   549
Edouard@252
   550
    cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
Edouard@209
   551
            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
Edouard@252
   552
            netpgp_getvar(&netpgp, "cipher"), 
Edouard@209
   553
            1 /* takes raw OpenPGP message */);
Edouard@209
   554
Edouard@209
   555
    if (cmem == NULL) {
Edouard@209
   556
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   557
        goto free_signedmem;
Edouard@209
   558
    }else{
Edouard@209
   559
Edouard@209
   560
        char *_buffer = NULL;
Edouard@209
   561
        size_t length = pgp_mem_len(cmem);
Edouard@174
   562
Edouard@209
   563
        // Allocate transferable buffer
Edouard@209
   564
        _buffer = malloc(length + 1);
Edouard@209
   565
        assert(_buffer);
Edouard@209
   566
        if (_buffer == NULL) {
Edouard@209
   567
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   568
            goto free_cmem;
Edouard@209
   569
        }
Edouard@209
   570
Edouard@209
   571
        memcpy(_buffer, pgp_mem_data(cmem), length);
Edouard@209
   572
Edouard@209
   573
        *ctext = _buffer;
Edouard@209
   574
        *csize = length;
Edouard@209
   575
        (*ctext)[*csize] = 0; // safeguard for naive users
Edouard@209
   576
        result = PEP_STATUS_OK;
Edouard@174
   577
    }
Edouard@174
   578
Edouard@209
   579
free_cmem :
Edouard@209
   580
    pgp_memory_free(cmem);
Edouard@209
   581
free_rcpts :
Edouard@209
   582
    pgp_keyring_free(rcpts);
Edouard@209
   583
free_signedmem :
Edouard@209
   584
    pgp_memory_free(signedmem);
Edouard@252
   585
unlock_netpgp:
Edouard@252
   586
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@175
   587
Edouard@174
   588
    return result;
Edouard@174
   589
}
Edouard@174
   590
Edouard@227
   591
/* return the hexdump as a string */
Edouard@227
   592
static unsigned
Edouard@227
   593
fpr_to_str (char **str, const uint8_t *fpr, size_t length)
Edouard@227
   594
{
Edouard@228
   595
    unsigned i;
Edouard@228
   596
    int	n;
Edouard@227
   597
Edouard@227
   598
    /* 5 char per byte (hexes + space) tuple -1 space at the end + null */
Edouard@227
   599
    *str = malloc((length / 2) * 5 - 1 + 1);
Edouard@227
   600
Edouard@227
   601
    if(*str == NULL)
Edouard@227
   602
        return 0;
Edouard@227
   603
Edouard@243
   604
    for (n = 0, i = 0 ; i < length - 2; i += 2) {
Edouard@243
   605
    	n += snprintf(&((*str)[n]), 6, "%02x%02x ", fpr[i], fpr[i+1]);
Edouard@228
   606
    }
Edouard@243
   607
    snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
Edouard@227
   608
Edouard@228
   609
    return 1;
Edouard@227
   610
}
Edouard@227
   611
Edouard@227
   612
static unsigned
Edouard@227
   613
str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
Edouard@227
   614
{
Edouard@227
   615
    unsigned i,j;
Edouard@227
   616
Edouard@227
   617
    *length = 0;
Edouard@227
   618
Edouard@227
   619
    while(*str && *length < PGP_FINGERPRINT_SIZE){
Edouard@227
   620
        while (*str == ' ') str++;
Edouard@227
   621
        for (j = 0; j < 2; j++) {
Edouard@227
   622
            uint8_t *byte = &fpr[*length];
Edouard@243
   623
            *byte = 0;
Edouard@227
   624
            for (i = 0; i < 2; i++) {
Edouard@227
   625
                if (i > 0)
Edouard@243
   626
                    *byte = *byte << 4;
Edouard@227
   627
                if (*str >= 'a' && *str <= 'f')
Edouard@227
   628
                    *byte += 10 + *str - 'a';
Edouard@227
   629
                else if (*str >= 'A' && *str <= 'F')
Edouard@227
   630
                    *byte += 10 + *str - 'A';
Edouard@227
   631
                else if (*str >= '0' && *str <= '9')
Edouard@227
   632
                    *byte += *str - '0';
Edouard@227
   633
                else 
Edouard@227
   634
                    return 0;
Edouard@227
   635
                str++;
Edouard@227
   636
            }
Edouard@243
   637
            (*length)++;
Edouard@227
   638
        }
Edouard@227
   639
    }
Edouard@227
   640
    return 1;
Edouard@227
   641
}
Edouard@227
   642
Edouard@228
   643
static PEP_STATUS import_key_or_keypair(netpgp_t *netpgp, pgp_key_t *newkey){
Edouard@228
   644
    pgp_key_t	pubkey;
Edouard@228
   645
    unsigned public;
Edouard@228
   646
    PEP_STATUS result;
Edouard@243
   647
    
Edouard@271
   648
    /* XXX TODO : check key is valid */
Edouard@271
   649
    /* XXX TODO : replace/update key if already in ring */
Edouard@271
   650
Edouard@228
   651
    if ((public = (newkey->type == PGP_PTAG_CT_PUBLIC_KEY))){
Edouard@228
   652
        pubkey = *newkey;
Edouard@228
   653
    } else {
Edouard@228
   654
        // Duplicate key as public only
Edouard@243
   655
        bzero(&pubkey, sizeof(pubkey));
Edouard@228
   656
        if (!pgp_keydata_dup(&pubkey, newkey, 1 /* make_public */)){
Edouard@228
   657
            return PEP_OUT_OF_MEMORY;
Edouard@228
   658
        }
Edouard@228
   659
    }
Edouard@228
   660
Edouard@252
   661
    // Append key to netpgp's rings (key ownership transfered)
Edouard@228
   662
    if (!public && !pgp_keyring_add(netpgp->secring, newkey)){
Edouard@228
   663
        result = PEP_OUT_OF_MEMORY;
Edouard@228
   664
        goto free_pubkey;
Edouard@228
   665
    } else if (!pgp_keyring_add(netpgp->pubring, &pubkey)){
Edouard@228
   666
        result = PEP_OUT_OF_MEMORY;
Edouard@228
   667
        goto pop_secring;
Edouard@228
   668
    }
Edouard@228
   669
Edouard@228
   670
    // save rings 
Edouard@228
   671
    if (netpgp_save_pubring(netpgp) && 
Edouard@228
   672
        (!public || netpgp_save_secring(netpgp)))
Edouard@228
   673
    {
Edouard@228
   674
        /* free nothing, everything transfered */
Edouard@228
   675
        return PEP_STATUS_OK;
Edouard@228
   676
    } else {
Edouard@228
   677
        /* XXX in case only pubring save succeed
Edouard@228
   678
         * pubring file is left as-is, but backup restore
Edouard@228
   679
         * could be attempted if such corner case matters */
Edouard@228
   680
        result = PEP_UNKNOWN_ERROR;
Edouard@228
   681
    }
Edouard@228
   682
Edouard@228
   683
pop_pubring:
Edouard@228
   684
    ((pgp_keyring_t *)netpgp->pubring)->keyc--;
Edouard@228
   685
pop_secring:
Edouard@228
   686
    ((pgp_keyring_t *)netpgp->secring)->keyc--;
Edouard@228
   687
free_pubkey:
Edouard@228
   688
    pgp_key_free(&pubkey);
Edouard@228
   689
Edouard@228
   690
    return result;
Edouard@228
   691
}
Edouard@228
   692
Edouard@174
   693
PEP_STATUS pgp_generate_keypair(
Edouard@174
   694
    PEP_SESSION session, pEp_identity *identity
Edouard@174
   695
    )
Edouard@174
   696
{
Edouard@228
   697
    pgp_key_t	newkey;
Edouard@225
   698
Edouard@225
   699
    PEP_STATUS result;
Edouard@228
   700
    char newid[1024];
Edouard@225
   701
    const char *hashalg;
Edouard@225
   702
    const char *cipher;
Edouard@174
   703
Edouard@174
   704
    assert(session);
Edouard@174
   705
    assert(identity);
Edouard@174
   706
    assert(identity->address);
Edouard@174
   707
    assert(identity->fpr == NULL);
Edouard@174
   708
    assert(identity->username);
Edouard@174
   709
Edouard@225
   710
    if(!session || !identity || 
Edouard@225
   711
       !identity->address || identity->fpr || !identity->username)
Edouard@225
   712
        return PEP_UNKNOWN_ERROR;
Edouard@174
   713
Edouard@263
   714
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   715
        return PEP_UNKNOWN_ERROR;
Edouard@252
   716
    }
Edouard@225
   717
Edouard@225
   718
    if(snprintf(newid, sizeof(newid),
Edouard@225
   719
        "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
Edouard@252
   720
        result =  PEP_BUFFER_TOO_SMALL;
Edouard@252
   721
        goto unlock_netpgp;
Edouard@174
   722
    }
Edouard@225
   723
    
Edouard@252
   724
    hashalg = netpgp_getvar(&netpgp, "hash");
Edouard@252
   725
    cipher = netpgp_getvar(&netpgp, "cipher");
Edouard@174
   726
Edouard@225
   727
    bzero(&newkey, sizeof(newkey));
Edouard@174
   728
Edouard@225
   729
    // Generate the key
Edouard@225
   730
    if (!pgp_rsa_generate_keypair(&newkey, 4096, 65537UL, hashalg, cipher,
Edouard@225
   731
                                  (const uint8_t *) "", (const size_t) 0) ||
Edouard@228
   732
        !pgp_add_selfsigned_userid(&newkey, (uint8_t *)newid)) {
Edouard@228
   733
        result = PEP_CANNOT_CREATE_KEY;
Edouard@228
   734
        goto free_newkey;
Edouard@228
   735
    }
Edouard@225
   736
Edouard@225
   737
    // TODO "Expire-Date: 1y\n";
Edouard@225
   738
Edouard@174
   739
Edouard@252
   740
    result = import_key_or_keypair(&netpgp, &newkey);
Edouard@225
   741
Edouard@228
   742
    if (result == PEP_STATUS_OK) {
Edouard@254
   743
        char *fprstr = NULL;
Edouard@254
   744
        fpr_to_str(&fprstr,
Edouard@254
   745
                   newkey.sigfingerprint.fingerprint,
Edouard@254
   746
                   newkey.sigfingerprint.length);
Edouard@254
   747
        if (fprstr == NULL) {
Edouard@254
   748
            result = PEP_OUT_OF_MEMORY;
Edouard@254
   749
            goto free_newkey;
Edouard@254
   750
        } 
Edouard@228
   751
        identity->fpr = fprstr;
Edouard@228
   752
        /* free nothing, everything transfered */
Edouard@252
   753
        result = PEP_STATUS_OK;
Edouard@252
   754
        goto unlock_netpgp;
Edouard@225
   755
    }
Edouard@174
   756
Edouard@228
   757
free_newkey:
Edouard@228
   758
    pgp_key_free(&newkey);
Edouard@252
   759
unlock_netpgp:
Edouard@252
   760
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
   761
Edouard@225
   762
    return result;
Edouard@174
   763
}
Edouard@174
   764
Edouard@227
   765
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
Edouard@174
   766
{
Edouard@227
   767
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@227
   768
    size_t length;
Edouard@227
   769
Edouard@227
   770
    PEP_STATUS result;
Edouard@227
   771
Edouard@174
   772
    assert(session);
Edouard@174
   773
    assert(fpr);
Edouard@174
   774
Edouard@227
   775
    if (!session || !fpr)
Edouard@174
   776
        return PEP_UNKNOWN_ERROR;
Edouard@174
   777
Edouard@263
   778
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   779
        return PEP_UNKNOWN_ERROR;
Edouard@252
   780
    }
Edouard@227
   781
    
Edouard@227
   782
    if (str_to_fpr(fprstr, fpr, &length)) {
Edouard@252
   783
        unsigned insec = pgp_deletekeybyfpr(netpgp.io,
Edouard@252
   784
                                (pgp_keyring_t *)netpgp.secring, 
Edouard@244
   785
                                (const uint8_t *)fpr, length);
Edouard@252
   786
        unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
Edouard@252
   787
                                (pgp_keyring_t *)netpgp.pubring, 
Edouard@244
   788
                                (const uint8_t *)fpr, length);
Edouard@244
   789
        if(!insec && !inpub){
Edouard@244
   790
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   791
            goto unlock_netpgp;
Edouard@244
   792
        } else {
Edouard@244
   793
            result = PEP_STATUS_OK;
Edouard@227
   794
        }
Edouard@227
   795
    }else{
Edouard@252
   796
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   797
        goto unlock_netpgp;
Edouard@227
   798
    }
Edouard@174
   799
Edouard@227
   800
    // save rings (key ownership transfered)
Edouard@252
   801
    if (netpgp_save_pubring(&netpgp) && 
Edouard@252
   802
        netpgp_save_secring(&netpgp))
Edouard@227
   803
    {
Edouard@227
   804
        result = PEP_STATUS_OK;
Edouard@227
   805
    }else{
Edouard@227
   806
        result = PEP_UNKNOWN_ERROR;
Edouard@227
   807
    }
Edouard@227
   808
Edouard@252
   809
unlock_netpgp:
Edouard@252
   810
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   811
Edouard@227
   812
    return result;
Edouard@174
   813
}
Edouard@174
   814
Edouard@228
   815
#define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----\\s*$"
Edouard@179
   816
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data, size_t size)
Edouard@174
   817
{
Edouard@228
   818
Edouard@228
   819
    pgp_memory_t *mem;
Edouard@228
   820
    pgp_keyring_t tmpring;
Edouard@271
   821
    unsigned i = 0;
Edouard@228
   822
Edouard@271
   823
    PEP_STATUS result = PEP_STATUS_OK;
Edouard@228
   824
Edouard@174
   825
    assert(session);
Edouard@174
   826
    assert(key_data);
Edouard@174
   827
Edouard@228
   828
    if(!session || !key_data) 
Edouard@174
   829
        return PEP_UNKNOWN_ERROR;
Edouard@228
   830
Edouard@263
   831
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   832
        return PEP_UNKNOWN_ERROR;
Edouard@252
   833
    }
Edouard@228
   834
Edouard@228
   835
    mem = pgp_memory_new();
Edouard@228
   836
    if (mem == NULL) {
Edouard@252
   837
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   838
        goto unlock_netpgp;
Edouard@228
   839
    }
Edouard@228
   840
    pgp_memory_add(mem, (const uint8_t*)key_data, size);
Edouard@228
   841
Edouard@244
   842
    bzero(&tmpring, sizeof(tmpring));
Edouard@244
   843
Edouard@252
   844
    if (pgp_keyring_read_from_mem(netpgp.io, &tmpring, 
Edouard@228
   845
                                  _armoured(key_data, size, ARMOR_KEY_HEAD),
Edouard@228
   846
                                  mem) == 0){
Edouard@228
   847
        result = PEP_ILLEGAL_VALUE;
Edouard@228
   848
    }else if (tmpring.keyc == 0){
Edouard@228
   849
        result = PEP_UNKNOWN_ERROR;
Edouard@271
   850
    }else while(result == PEP_STATUS_OK && i < tmpring.keyc){
Edouard@271
   851
        result = import_key_or_keypair(&netpgp, &tmpring.keys[i++]);
Edouard@228
   852
    }
Edouard@228
   853
    
Edouard@228
   854
    pgp_memory_free(mem);
Edouard@228
   855
Edouard@244
   856
    if (result == PEP_STATUS_OK){
Edouard@244
   857
        pgp_keyring_free(&tmpring);
Edouard@244
   858
    }else{
Edouard@228
   859
        pgp_keyring_purge(&tmpring);
Edouard@228
   860
    }
Edouard@228
   861
Edouard@252
   862
unlock_netpgp:
Edouard@252
   863
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   864
Edouard@228
   865
    return result;
Edouard@174
   866
}
Edouard@174
   867
Edouard@179
   868
PEP_STATUS pgp_export_keydata(
Edouard@228
   869
    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
Edouard@174
   870
    )
Edouard@174
   871
{
Edouard@228
   872
    pgp_key_t *key;
Edouard@228
   873
	pgp_output_t *output;
Edouard@228
   874
    pgp_memory_t *mem;
Edouard@228
   875
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@228
   876
    size_t fprlen;
Edouard@228
   877
Edouard@228
   878
    PEP_STATUS result;
Edouard@174
   879
    char *buffer;
Edouard@228
   880
    size_t buflen;
Edouard@174
   881
Edouard@174
   882
    assert(session);
Edouard@243
   883
    assert(fprstr);
Edouard@174
   884
    assert(key_data);
Edouard@174
   885
    assert(size);
Edouard@174
   886
Edouard@243
   887
    if (!session || !fprstr || !key_data || !size)
Edouard@174
   888
        return PEP_UNKNOWN_ERROR;
Edouard@174
   889
Edouard@263
   890
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   891
        return PEP_UNKNOWN_ERROR;
Edouard@252
   892
    }
Edouard@252
   893
Edouard@228
   894
    if (str_to_fpr(fprstr, fpr, &fprlen)) {
Edouard@252
   895
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring, 
Edouard@228
   896
                                                fpr, fprlen,
Edouard@254
   897
                                                NULL)) == NULL) {
Edouard@252
   898
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   899
            goto unlock_netpgp;
Edouard@228
   900
        }
Edouard@228
   901
    }else{
Edouard@252
   902
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   903
        goto unlock_netpgp;
Edouard@228
   904
    }
Edouard@228
   905
    
Edouard@228
   906
	pgp_setup_memory_write(&output, &mem, 128);
Edouard@174
   907
Edouard@228
   908
    if (mem == NULL || output == NULL) {
Edouard@252
   909
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   910
        goto unlock_netpgp;
Edouard@174
   911
    }
Edouard@174
   912
Edouard@228
   913
    if (!pgp_write_xfer_pubkey(output, key, 1)) {
Edouard@228
   914
        result = PEP_UNKNOWN_ERROR;
Edouard@228
   915
        goto free_mem;
Edouard@228
   916
    }
Edouard@228
   917
Edouard@228
   918
    buffer = NULL;
Edouard@228
   919
    buflen = pgp_mem_len(mem);
Edouard@228
   920
Edouard@228
   921
    // Allocate transferable buffer
Edouard@228
   922
    buffer = malloc(buflen + 1);
Edouard@228
   923
    assert(buffer);
Edouard@228
   924
    if (buffer == NULL) {
Edouard@228
   925
        result = PEP_OUT_OF_MEMORY;
Edouard@228
   926
        goto free_mem;
Edouard@228
   927
    }
Edouard@228
   928
Edouard@228
   929
    memcpy(buffer, pgp_mem_data(mem), buflen);
Edouard@174
   930
Edouard@174
   931
    *key_data = buffer;
Edouard@228
   932
    *size = buflen;
Edouard@228
   933
    (*key_data)[*size] = 0; // safeguard for naive users
Edouard@228
   934
    result = PEP_STATUS_OK;
Edouard@174
   935
Edouard@228
   936
free_mem :
Edouard@228
   937
	pgp_teardown_memory_write(output, mem);
Edouard@252
   938
unlock_netpgp:
Edouard@252
   939
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
   940
Edouard@228
   941
    return result;
Edouard@174
   942
}
Edouard@174
   943
Edouard@271
   944
struct HKP_answer {
Edouard@271
   945
  char *memory;
Edouard@271
   946
  size_t size;
Edouard@271
   947
};
Edouard@271
   948
 
Edouard@271
   949
static size_t
Edouard@271
   950
HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
Edouard@271
   951
{
Edouard@271
   952
  size_t realsize = size * nmemb;
Edouard@271
   953
  struct HKP_answer *mem = (struct HKP_answer *)userp;
Edouard@271
   954
 
Edouard@271
   955
  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
Edouard@271
   956
  if(mem->memory == NULL) {
Edouard@271
   957
    mem->size = 0;
Edouard@271
   958
    return 0;
Edouard@271
   959
  }
Edouard@271
   960
 
Edouard@271
   961
  memcpy(&(mem->memory[mem->size]), contents, realsize);
Edouard@271
   962
  mem->size += realsize;
Edouard@271
   963
  mem->memory[mem->size] = 0;
Edouard@271
   964
 
Edouard@271
   965
  return realsize;
Edouard@271
   966
}
Edouard@271
   967
Edouard@174
   968
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
Edouard@174
   969
{
Edouard@271
   970
    static const char *ks_cmd = "http://keys.gnupg.net:11371/pks/lookup?"
Edouard@271
   971
                                "op=get&options=mr&exact=on&"
Edouard@271
   972
                                "search=";
Edouard@271
   973
    char *encoded_pattern;
Edouard@271
   974
    char *request = NULL;
Edouard@271
   975
    struct HKP_answer answer;
Edouard@271
   976
    CURLcode curlres;
Edouard@271
   977
       
Edouard@271
   978
    PEP_STATUS result;
Edouard@271
   979
Edouard@271
   980
    CURL *curl;
Edouard@271
   981
Edouard@174
   982
    assert(session);
Edouard@174
   983
    assert(pattern);
Edouard@174
   984
Edouard@271
   985
    if (!session || !pattern )
Edouard@271
   986
        return PEP_UNKNOWN_ERROR;
Edouard@271
   987
Edouard@271
   988
    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
Edouard@271
   989
        return PEP_UNKNOWN_ERROR;
Edouard@271
   990
    }
Edouard@271
   991
Edouard@252
   992
    curl = session->ctx.curl;
Edouard@252
   993
Edouard@271
   994
    encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
Edouard@271
   995
    if(!encoded_pattern){
Edouard@271
   996
        result = PEP_OUT_OF_MEMORY;
Edouard@271
   997
        goto unlock_curl;
Edouard@271
   998
    }
Edouard@271
   999
Edouard@271
  1000
    if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
Edouard@271
  1001
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1002
        goto free_encoded_pattern;
Edouard@271
  1003
    }
Edouard@174
  1004
Edouard@271
  1005
    //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
Edouard@271
  1006
    stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
Edouard@271
  1007
Edouard@271
  1008
    curl_easy_setopt(curl, CURLOPT_URL,request);
Edouard@271
  1009
Edouard@271
  1010
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
Edouard@271
  1011
Edouard@271
  1012
    answer.memory = NULL;
Edouard@271
  1013
    answer.size = 0;
Edouard@271
  1014
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
Edouard@174
  1015
Edouard@271
  1016
    curlres = curl_easy_perform(curl);
Edouard@271
  1017
    if(curlres != CURLE_OK) {
Edouard@271
  1018
        result = PEP_GET_KEY_FAILED;
Edouard@271
  1019
        goto free_request;
Edouard@271
  1020
    }
Edouard@271
  1021
Edouard@271
  1022
    if(!answer.memory || !answer.size) {
Edouard@271
  1023
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1024
        goto free_request;
Edouard@271
  1025
    }
Edouard@174
  1026
Edouard@271
  1027
    printf("request :\n %s\n\nanswer :\n%s\n", request, answer);
Edouard@271
  1028
    result = pgp_import_keydata(session, 
Edouard@271
  1029
                                answer.memory, 
Edouard@271
  1030
                                answer.size);
Edouard@271
  1031
Edouard@271
  1032
free_answer:
Edouard@271
  1033
    free(answer.memory);
Edouard@271
  1034
free_request:
Edouard@271
  1035
    free(request);
Edouard@271
  1036
free_encoded_pattern:
Edouard@271
  1037
    curl_free(encoded_pattern);
Edouard@271
  1038
unlock_curl:
Edouard@271
  1039
    pthread_mutex_unlock(&session->ctx.curl_mutex);
Edouard@271
  1040
Edouard@271
  1041
    return result;
Edouard@174
  1042
}
Edouard@174
  1043
Edouard@254
  1044
PEP_STATUS add_key_fpr_to_stringlist(stringlist_t **keylist, pgp_key_t *key)
Edouard@254
  1045
{
Edouard@254
  1046
    char *newfprstr = NULL;
Edouard@254
  1047
Edouard@254
  1048
    fpr_to_str(&newfprstr,
Edouard@254
  1049
               key->sigfingerprint.fingerprint,
Edouard@254
  1050
               key->sigfingerprint.length);
Edouard@254
  1051
Edouard@254
  1052
    if (newfprstr == NULL) {
Edouard@254
  1053
        return PEP_OUT_OF_MEMORY;
Edouard@254
  1054
    } else { 
Edouard@254
  1055
Edouard@254
  1056
        *keylist = stringlist_add(*keylist, newfprstr);
Edouard@254
  1057
        if (*keylist == NULL) {
Edouard@254
  1058
            free(newfprstr);
Edouard@254
  1059
            return PEP_OUT_OF_MEMORY;
Edouard@254
  1060
        }
Edouard@254
  1061
    }
Edouard@254
  1062
    return PEP_STATUS_OK;
Edouard@254
  1063
}
Edouard@254
  1064
Edouard@174
  1065
PEP_STATUS pgp_find_keys(
Edouard@174
  1066
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
Edouard@174
  1067
    )
Edouard@174
  1068
{
Edouard@254
  1069
    stringlist_t *_keylist, *_k;
Edouard@254
  1070
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@254
  1071
    size_t length;
Edouard@254
  1072
    pgp_key_t *key;
Edouard@254
  1073
    char *newfprstr = NULL;
Edouard@254
  1074
Edouard@254
  1075
    PEP_STATUS result;
Edouard@174
  1076
Edouard@174
  1077
    assert(session);
Edouard@174
  1078
    assert(pattern);
Edouard@174
  1079
    assert(keylist);
Edouard@174
  1080
Edouard@254
  1081
    if (!session || !pattern || !keylist )
Edouard@254
  1082
        return PEP_UNKNOWN_ERROR;
Edouard@174
  1083
Edouard@263
  1084
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@174
  1085
        return PEP_UNKNOWN_ERROR;
Edouard@254
  1086
    }
Edouard@254
  1087
Edouard@254
  1088
    *keylist = NULL;
Edouard@254
  1089
    _keylist = new_stringlist(NULL);
Edouard@254
  1090
    if (_k == NULL) {
Edouard@254
  1091
        result = PEP_OUT_OF_MEMORY;
Edouard@254
  1092
        goto unlock_netpgp;
Edouard@254
  1093
    }
Edouard@254
  1094
    _k = _keylist;
Edouard@254
  1095
Edouard@254
  1096
    // Try find a fingerprint in pattern
Edouard@254
  1097
    if (str_to_fpr(pattern, fpr, &length)) {
Edouard@254
  1098
Edouard@254
  1099
        // Only one fingerprint can match
Edouard@254
  1100
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(
Edouard@254
  1101
                        netpgp.io,
Edouard@254
  1102
                        (pgp_keyring_t *)netpgp.pubring, 
Edouard@254
  1103
                        (const uint8_t *)fpr, length,
Edouard@254
  1104
                        NULL)) == NULL) {
Edouard@254
  1105
Edouard@254
  1106
            result = PEP_KEY_NOT_FOUND;
Edouard@254
  1107
            goto unlock_netpgp;
Edouard@254
  1108
        }
Edouard@174
  1109
Edouard@254
  1110
        result = add_key_fpr_to_stringlist(&_k, key);
Edouard@254
  1111
Edouard@254
  1112
    } else {
Edouard@254
  1113
        // Search by name for pattern. Can match many.
Edouard@254
  1114
        unsigned from = 0;
Edouard@263
  1115
        result = PEP_KEY_NOT_FOUND;
Edouard@254
  1116
        while((key = (pgp_key_t *)pgp_getnextkeybyname(
Edouard@254
  1117
                        netpgp.io,
Edouard@254
  1118
                        (pgp_keyring_t *)netpgp.pubring, 
Edouard@254
  1119
			            (const char *)pattern,
Edouard@254
  1120
                        &from)) != NULL) {
Edouard@254
  1121
Edouard@254
  1122
            result = add_key_fpr_to_stringlist(&_k, key);
Edouard@254
  1123
            if (result != PEP_STATUS_OK)
Edouard@254
  1124
                goto free_keylist;
Edouard@174
  1125
Edouard@254
  1126
            from++;
Edouard@254
  1127
        }
Edouard@254
  1128
    }
Edouard@254
  1129
Edouard@254
  1130
    if (result == PEP_STATUS_OK) {
Edouard@254
  1131
        *keylist = _keylist;
Edouard@254
  1132
        // Transfer ownership, no free
Edouard@254
  1133
        goto unlock_netpgp;
Edouard@254
  1134
    }
Edouard@254
  1135
Edouard@254
  1136
free_keylist:
Edouard@254
  1137
    free_stringlist(_keylist);
Edouard@254
  1138
Edouard@254
  1139
unlock_netpgp:
Edouard@254
  1140
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@254
  1141
Edouard@254
  1142
    return result;
Edouard@174
  1143
}
Edouard@174
  1144
Edouard@174
  1145
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
Edouard@174
  1146
{
Edouard@174
  1147
    assert(session);
Edouard@174
  1148
    assert(pattern);
Edouard@174
  1149
Edouard@174
  1150
    /* TODO send key */
Edouard@174
  1151
Edouard@174
  1152
        return PEP_CANNOT_SEND_KEY;
Edouard@174
  1153
        return PEP_STATUS_OK;
Edouard@174
  1154
}
Edouard@174
  1155
Edouard@174
  1156
Edouard@174
  1157
PEP_STATUS pgp_get_key_rating(
Edouard@174
  1158
    PEP_SESSION session,
Edouard@174
  1159
    const char *fpr,
Edouard@174
  1160
    PEP_comm_type *comm_type
Edouard@174
  1161
    )
Edouard@174
  1162
{
Edouard@174
  1163
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@174
  1164
Edouard@174
  1165
    assert(session);
Edouard@174
  1166
    assert(fpr);
Edouard@174
  1167
    assert(comm_type);
Edouard@174
  1168
Edouard@174
  1169
    *comm_type = PEP_ct_unknown;
Edouard@174
  1170
Edouard@174
  1171
    /* TODO get key from fpr */
Edouard@174
  1172
    return PEP_UNKNOWN_ERROR;
Edouard@174
  1173
    return PEP_GET_KEY_FAILED;
Edouard@174
  1174
Edouard@174
  1175
    switch (/*TODO key->protocol*/ 4) {
Edouard@174
  1176
    case /* TODO  OpenPGP */0:
Edouard@174
  1177
    case /* TODO DEFAULT */1:
Edouard@174
  1178
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
Edouard@174
  1179
        break;
Edouard@174
  1180
    case /* TODO CMS */2:
Edouard@174
  1181
        *comm_type = PEP_ct_CMS_unconfirmed;
Edouard@174
  1182
        break;
Edouard@174
  1183
    default:
Edouard@174
  1184
        *comm_type = PEP_ct_unknown;
Edouard@174
  1185
        return PEP_STATUS_OK;
Edouard@174
  1186
    }
Edouard@174
  1187
Edouard@174
  1188
        for (; 1 == 0; /* Each subkeys */ ) {
Edouard@174
  1189
            if (/* TODO length */0 < 1024)
Edouard@174
  1190
                *comm_type = PEP_ct_key_too_short;
Edouard@174
  1191
            else if (
Edouard@174
  1192
                (
Edouard@174
  1193
                (   /* TODO pubkey_algo == RSA  */ 0)
Edouard@174
  1194
                || (/* TODO pubkey_algo == RSA_E*/ 0)
Edouard@174
  1195
                || (/* TODO pubkey_algo == RSA_S*/ 0)
Edouard@174
  1196
                )
Edouard@174
  1197
                && /* sk->length */0 == 1024
Edouard@174
  1198
                )
Edouard@174
  1199
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
Edouard@174
  1200
Edouard@174
  1201
            if (/* TODO invalid */ 1) {
Edouard@174
  1202
                *comm_type = PEP_ct_key_b0rken;
Edouard@174
  1203
                break;
Edouard@174
  1204
            }
Edouard@174
  1205
            if (/* TODO expired */ 1) {
Edouard@174
  1206
                *comm_type = PEP_ct_key_expired;
Edouard@174
  1207
                break;
Edouard@174
  1208
            }
Edouard@175
  1209
            if (/* TODO revoked*/ 1) {
Edouard@174
  1210
                *comm_type = PEP_ct_key_revoked;
Edouard@174
  1211
                break;
Edouard@174
  1212
            }
Edouard@174
  1213
        }
Edouard@174
  1214
        *comm_type = PEP_ct_unknown;
Edouard@174
  1215
        return PEP_OUT_OF_MEMORY;
Edouard@174
  1216
        return PEP_UNKNOWN_ERROR;
Edouard@174
  1217
Edouard@174
  1218
Edouard@174
  1219
    return status;
Edouard@174
  1220
}
Edouard@210
  1221
Edouard@210
  1222
PEP_STATUS pgp_renew_key(
Edouard@210
  1223
        PEP_SESSION session,
Edouard@210
  1224
        const char *fpr,
Edouard@210
  1225
        const timestamp *ts
Edouard@210
  1226
    )
Edouard@210
  1227
{
Edouard@210
  1228
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
  1229
    char date_text[12];
Edouard@210
  1230
Edouard@210
  1231
    assert(session);
Edouard@210
  1232
    assert(fpr);
Edouard@210
  1233
Edouard@210
  1234
    snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
Edouard@210
  1235
            ts->tm_mon + 1, ts->tm_mday);
Edouard@210
  1236
Edouard@210
  1237
Edouard@210
  1238
        return PEP_UNKNOWN_ERROR;
Edouard@210
  1239
    return PEP_STATUS_OK;
Edouard@210
  1240
}
Edouard@210
  1241
Edouard@226
  1242
PEP_STATUS pgp_revoke_key(
Edouard@226
  1243
        PEP_SESSION session,
Edouard@226
  1244
        const char *fpr,
Edouard@226
  1245
        const char *reason
Edouard@226
  1246
    )
Edouard@210
  1247
{
Edouard@210
  1248
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
  1249
    
Edouard@210
  1250
    assert(session);
Edouard@210
  1251
    assert(fpr);
Edouard@210
  1252
Edouard@210
  1253
        return PEP_UNKNOWN_ERROR;
Edouard@210
  1254
Edouard@210
  1255
    return PEP_STATUS_OK;
Edouard@210
  1256
}
Edouard@210
  1257
Edouard@226
  1258
PEP_STATUS pgp_key_expired(
Edouard@226
  1259
        PEP_SESSION session,
Edouard@226
  1260
        const char *fpr,
Edouard@226
  1261
        bool *expired
Edouard@226
  1262
    )
Edouard@226
  1263
{
Edouard@226
  1264
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@226
  1265
Edouard@226
  1266
    assert(session);
Edouard@226
  1267
    assert(fpr);
Edouard@226
  1268
    assert(expired);
Edouard@226
  1269
Edouard@226
  1270
    *expired = false;
Edouard@226
  1271
Edouard@226
  1272
    if (status != PEP_STATUS_OK)
Edouard@226
  1273
        return status;
Edouard@226
  1274
Edouard@226
  1275
    return PEP_STATUS_OK;
Edouard@226
  1276
}
Edouard@226
  1277