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