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