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