src/pgp_netpgp.c
author Edouard Tisserant
Sun, 28 Jun 2015 13:45:30 +0200
changeset 329 27daa4a5abc4
parent 328 7a64ff9fdc9d
child 334 3036eafdd1eb
permissions -rw-r--r--
netpgp : pgp_renew_key (untested). pEpEnginge/netpgp interface completed
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@313
   747
    // Generate the key
Edouard@313
   748
    if (!pgp_rsa_generate_keypair(&newseckey, 4096, 65537UL, hashalg, cipher,
Edouard@327
   749
                                  (const uint8_t *) "", (const size_t) 0))
Edouard@327
   750
    {
Edouard@313
   751
        result = PEP_CANNOT_CREATE_KEY;
Edouard@313
   752
        goto free_seckey;
Edouard@225
   753
    }
Edouard@174
   754
Edouard@316
   755
    /* make a public key out of generated secret key */
Edouard@327
   756
    if((newpubkey = pgp_ensure_pubkey(
Edouard@316
   757
            netpgp.pubring,
Edouard@316
   758
            &newseckey.key.seckey.pubkey,
Edouard@327
   759
            newseckey.pubkeyid))==NULL)
Edouard@327
   760
    {
Edouard@316
   761
        result = PEP_OUT_OF_MEMORY;
Edouard@316
   762
        goto free_seckey;
Edouard@316
   763
    }
Edouard@316
   764
Edouard@328
   765
    // "Expire-Date: 1y\n";
Edouard@329
   766
    if (!pgp_add_selfsigned_userid(&newseckey, newpubkey, 
Edouard@329
   767
                                  (uint8_t *)newid, 365*24*3600))
Edouard@327
   768
    {
Edouard@327
   769
        result = PEP_CANNOT_CREATE_KEY;
Edouard@327
   770
        goto delete_pubkey;
Edouard@327
   771
    }
Edouard@313
   772
Edouard@327
   773
    if (newpubkey == NULL)
Edouard@327
   774
    {
Edouard@327
   775
        result = PEP_OUT_OF_MEMORY;
Edouard@327
   776
        goto delete_pubkey;
Edouard@327
   777
    }
Edouard@313
   778
Edouard@313
   779
    // Append key to netpgp's rings (key ownership transfered)
Edouard@313
   780
    if (!pgp_keyring_add(netpgp.secring, &newseckey)){
Edouard@313
   781
        result = PEP_OUT_OF_MEMORY;
Edouard@316
   782
        goto delete_pubkey;
Edouard@316
   783
    } 
Edouard@313
   784
Edouard@313
   785
    // save rings 
Edouard@313
   786
    if (netpgp_save_pubring(&netpgp) && netpgp_save_secring(&netpgp))
Edouard@313
   787
    {
Edouard@316
   788
        char *fprstr = NULL;
Edouard@316
   789
        fpr_to_str(&fprstr,
Edouard@316
   790
                   newseckey.pubkeyfpr.fingerprint,
Edouard@316
   791
                   newseckey.pubkeyfpr.length);
Edouard@316
   792
Edouard@316
   793
        if (fprstr == NULL) {
Edouard@316
   794
            result = PEP_OUT_OF_MEMORY;
Edouard@316
   795
            goto pop_secring;
Edouard@316
   796
        } 
Edouard@316
   797
Edouard@316
   798
        /* keys saved, pass fingerprint back */
Edouard@313
   799
        identity->fpr = fprstr;
Edouard@313
   800
        result = PEP_STATUS_OK;
Edouard@316
   801
Edouard@313
   802
        /* free nothing, everything transfered */
Edouard@313
   803
        goto unlock_netpgp;
Edouard@313
   804
    } else {
Edouard@313
   805
        /* XXX in case only pubring save succeed
Edouard@313
   806
         * pubring file is left as-is, but backup restore
Edouard@313
   807
         * could be attempted if such corner case matters */
Edouard@313
   808
        result = PEP_UNKNOWN_ERROR;
Edouard@313
   809
    }
Edouard@313
   810
Edouard@313
   811
pop_secring:
Edouard@313
   812
    ((pgp_keyring_t *)netpgp.secring)->keyc--;
Edouard@316
   813
delete_pubkey:
Edouard@316
   814
    pgp_deletekeybyfpr(netpgp.io,
Edouard@316
   815
                    (pgp_keyring_t *)netpgp.pubring, 
Edouard@316
   816
                    newseckey.pubkeyfpr.fingerprint,
Edouard@316
   817
                    newseckey.pubkeyfpr.length);
Edouard@313
   818
free_seckey:
Edouard@313
   819
    pgp_key_free(&newseckey);
Edouard@252
   820
unlock_netpgp:
Edouard@252
   821
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
   822
Edouard@225
   823
    return result;
Edouard@174
   824
}
Edouard@174
   825
Edouard@227
   826
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
Edouard@174
   827
{
Edouard@227
   828
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@227
   829
    size_t length;
Edouard@227
   830
Edouard@227
   831
    PEP_STATUS result;
Edouard@227
   832
Edouard@174
   833
    assert(session);
Edouard@174
   834
    assert(fpr);
Edouard@174
   835
Edouard@227
   836
    if (!session || !fpr)
Edouard@174
   837
        return PEP_UNKNOWN_ERROR;
Edouard@174
   838
Edouard@263
   839
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   840
        return PEP_UNKNOWN_ERROR;
Edouard@252
   841
    }
Edouard@227
   842
    
Edouard@227
   843
    if (str_to_fpr(fprstr, fpr, &length)) {
Edouard@252
   844
        unsigned insec = pgp_deletekeybyfpr(netpgp.io,
Edouard@252
   845
                                (pgp_keyring_t *)netpgp.secring, 
Edouard@244
   846
                                (const uint8_t *)fpr, length);
Edouard@252
   847
        unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
Edouard@252
   848
                                (pgp_keyring_t *)netpgp.pubring, 
Edouard@244
   849
                                (const uint8_t *)fpr, length);
Edouard@244
   850
        if(!insec && !inpub){
Edouard@244
   851
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   852
            goto unlock_netpgp;
Edouard@244
   853
        } else {
Edouard@244
   854
            result = PEP_STATUS_OK;
Edouard@227
   855
        }
Edouard@227
   856
    }else{
Edouard@252
   857
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   858
        goto unlock_netpgp;
Edouard@227
   859
    }
Edouard@174
   860
Edouard@325
   861
    // save rings 
Edouard@252
   862
    if (netpgp_save_pubring(&netpgp) && 
Edouard@252
   863
        netpgp_save_secring(&netpgp))
Edouard@227
   864
    {
Edouard@227
   865
        result = PEP_STATUS_OK;
Edouard@227
   866
    }else{
Edouard@227
   867
        result = PEP_UNKNOWN_ERROR;
Edouard@227
   868
    }
Edouard@227
   869
Edouard@252
   870
unlock_netpgp:
Edouard@252
   871
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   872
Edouard@227
   873
    return result;
Edouard@174
   874
}
Edouard@174
   875
Edouard@228
   876
#define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----\\s*$"
Edouard@279
   877
PEP_STATUS pgp_import_keydata(
Edouard@279
   878
        PEP_SESSION session,
Edouard@279
   879
        const char *key_data, 
Edouard@279
   880
        size_t size
Edouard@279
   881
    )
Edouard@174
   882
{
Edouard@228
   883
    pgp_memory_t *mem;
Edouard@271
   884
    unsigned i = 0;
Edouard@228
   885
Edouard@271
   886
    PEP_STATUS result = PEP_STATUS_OK;
Edouard@228
   887
Edouard@174
   888
    assert(session);
Edouard@174
   889
    assert(key_data);
Edouard@174
   890
Edouard@228
   891
    if(!session || !key_data) 
Edouard@174
   892
        return PEP_UNKNOWN_ERROR;
Edouard@228
   893
Edouard@263
   894
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   895
        return PEP_UNKNOWN_ERROR;
Edouard@252
   896
    }
Edouard@228
   897
Edouard@228
   898
    mem = pgp_memory_new();
Edouard@228
   899
    if (mem == NULL) {
Edouard@252
   900
        result = PEP_OUT_OF_MEMORY;
Edouard@252
   901
        goto unlock_netpgp;
Edouard@228
   902
    }
Edouard@228
   903
    pgp_memory_add(mem, (const uint8_t*)key_data, size);
Edouard@228
   904
Edouard@313
   905
    if (pgp_keyring_read_from_mem(netpgp.io, netpgp.pubring, netpgp.secring, 
Edouard@228
   906
                                  _armoured(key_data, size, ARMOR_KEY_HEAD),
Edouard@228
   907
                                  mem) == 0){
Edouard@228
   908
        result = PEP_ILLEGAL_VALUE;
Edouard@313
   909
    }    
Edouard@313
   910
Edouard@228
   911
    pgp_memory_free(mem);
Edouard@228
   912
Edouard@325
   913
    // save rings 
Edouard@325
   914
    if (netpgp_save_pubring(&netpgp) && 
Edouard@325
   915
        netpgp_save_secring(&netpgp))
Edouard@325
   916
    {
Edouard@325
   917
        result = PEP_STATUS_OK;
Edouard@325
   918
    }else{
Edouard@325
   919
        result = PEP_UNKNOWN_ERROR;
Edouard@325
   920
    }
Edouard@325
   921
Edouard@252
   922
unlock_netpgp:
Edouard@252
   923
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@252
   924
Edouard@228
   925
    return result;
Edouard@174
   926
}
Edouard@174
   927
Edouard@318
   928
static PEP_STATUS _export_keydata(
Edouard@318
   929
    pgp_key_t *key,
Edouard@318
   930
    char **buffer,
Edouard@318
   931
    size_t *buflen
Edouard@318
   932
    )
Edouard@318
   933
{
Edouard@318
   934
    PEP_STATUS result;
Edouard@318
   935
	pgp_output_t *output;
Edouard@318
   936
    pgp_memory_t *mem;
Edouard@318
   937
	pgp_setup_memory_write(&output, &mem, 128);
Edouard@318
   938
Edouard@318
   939
    if (mem == NULL || output == NULL) {
Edouard@318
   940
        return PEP_OUT_OF_MEMORY;
Edouard@318
   941
    }
Edouard@318
   942
Edouard@318
   943
    if (!pgp_write_xfer_key(output, key, 1)) {
Edouard@318
   944
        result = PEP_UNKNOWN_ERROR;
Edouard@318
   945
        goto free_mem;
Edouard@318
   946
    }
Edouard@318
   947
Edouard@318
   948
    *buffer = NULL;
Edouard@318
   949
    *buflen = pgp_mem_len(mem);
Edouard@318
   950
Edouard@318
   951
    // Allocate transferable buffer
Edouard@318
   952
    *buffer = malloc(*buflen + 1);
Edouard@318
   953
    assert(*buffer);
Edouard@318
   954
    if (*buffer == NULL) {
Edouard@318
   955
        result = PEP_OUT_OF_MEMORY;
Edouard@318
   956
        goto free_mem;
Edouard@318
   957
    }
Edouard@318
   958
Edouard@318
   959
    memcpy(*buffer, pgp_mem_data(mem), *buflen);
Edouard@318
   960
    (*buffer)[*buflen] = 0; // safeguard for naive users
Edouard@318
   961
Edouard@318
   962
    return PEP_STATUS_OK;
Edouard@318
   963
Edouard@318
   964
free_mem :
Edouard@318
   965
	pgp_teardown_memory_write(output, mem);
Edouard@318
   966
Edouard@318
   967
    return result;
Edouard@318
   968
}
Edouard@318
   969
Edouard@179
   970
PEP_STATUS pgp_export_keydata(
Edouard@228
   971
    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
Edouard@174
   972
    )
Edouard@174
   973
{
Edouard@228
   974
    pgp_key_t *key;
Edouard@228
   975
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@228
   976
    size_t fprlen;
Edouard@228
   977
Edouard@228
   978
    PEP_STATUS result;
Edouard@174
   979
    char *buffer;
Edouard@228
   980
    size_t buflen;
Edouard@174
   981
Edouard@174
   982
    assert(session);
Edouard@243
   983
    assert(fprstr);
Edouard@174
   984
    assert(key_data);
Edouard@174
   985
    assert(size);
Edouard@174
   986
Edouard@243
   987
    if (!session || !fprstr || !key_data || !size)
Edouard@174
   988
        return PEP_UNKNOWN_ERROR;
Edouard@174
   989
Edouard@263
   990
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@252
   991
        return PEP_UNKNOWN_ERROR;
Edouard@252
   992
    }
Edouard@252
   993
Edouard@228
   994
    if (str_to_fpr(fprstr, fpr, &fprlen)) {
Edouard@252
   995
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring, 
Edouard@228
   996
                                                fpr, fprlen,
Edouard@254
   997
                                                NULL)) == NULL) {
Edouard@252
   998
            result = PEP_KEY_NOT_FOUND;
Edouard@252
   999
            goto unlock_netpgp;
Edouard@228
  1000
        }
Edouard@228
  1001
    }else{
Edouard@252
  1002
        result = PEP_OUT_OF_MEMORY;
Edouard@252
  1003
        goto unlock_netpgp;
Edouard@228
  1004
    }
Edouard@228
  1005
    
Edouard@318
  1006
    result = _export_keydata(key, &buffer, &buflen);
Edouard@318
  1007
    
Edouard@318
  1008
    if(result == PEP_STATUS_OK)
Edouard@318
  1009
    {
Edouard@318
  1010
        *key_data = buffer;
Edouard@318
  1011
        *size = buflen;
Edouard@318
  1012
        result = PEP_STATUS_OK;
Edouard@228
  1013
    }
Edouard@228
  1014
Edouard@252
  1015
unlock_netpgp:
Edouard@252
  1016
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@228
  1017
Edouard@228
  1018
    return result;
Edouard@174
  1019
}
Edouard@174
  1020
Edouard@271
  1021
struct HKP_answer {
Edouard@271
  1022
  char *memory;
Edouard@271
  1023
  size_t size;
Edouard@271
  1024
};
Edouard@271
  1025
 
Edouard@271
  1026
static size_t
Edouard@271
  1027
HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
Edouard@271
  1028
{
Edouard@271
  1029
  size_t realsize = size * nmemb;
Edouard@271
  1030
  struct HKP_answer *mem = (struct HKP_answer *)userp;
Edouard@271
  1031
 
Edouard@271
  1032
  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
Edouard@271
  1033
  if(mem->memory == NULL) {
Edouard@271
  1034
    mem->size = 0;
Edouard@271
  1035
    return 0;
Edouard@271
  1036
  }
Edouard@271
  1037
 
Edouard@271
  1038
  memcpy(&(mem->memory[mem->size]), contents, realsize);
Edouard@271
  1039
  mem->size += realsize;
Edouard@271
  1040
  mem->memory[mem->size] = 0;
Edouard@271
  1041
 
Edouard@271
  1042
  return realsize;
Edouard@271
  1043
}
Edouard@271
  1044
Edouard@323
  1045
#define HKP_SERVER "http://keys.gnupg.net:11371"
Edouard@323
  1046
// #define HKP_SERVER "http://127.0.0.1:11371"
Edouard@321
  1047
Edouard@174
  1048
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
Edouard@174
  1049
{
Edouard@321
  1050
    static const char *ks_cmd = HKP_SERVER
Edouard@321
  1051
                                "/pks/lookup?"
Edouard@271
  1052
                                "op=get&options=mr&exact=on&"
Edouard@271
  1053
                                "search=";
Edouard@271
  1054
    char *encoded_pattern;
Edouard@271
  1055
    char *request = NULL;
Edouard@271
  1056
    struct HKP_answer answer;
Edouard@271
  1057
    CURLcode curlres;
Edouard@271
  1058
       
Edouard@271
  1059
    PEP_STATUS result;
Edouard@271
  1060
Edouard@271
  1061
    CURL *curl;
Edouard@271
  1062
Edouard@174
  1063
    assert(session);
Edouard@174
  1064
    assert(pattern);
Edouard@174
  1065
Edouard@271
  1066
    if (!session || !pattern )
Edouard@271
  1067
        return PEP_UNKNOWN_ERROR;
Edouard@271
  1068
Edouard@271
  1069
    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
Edouard@271
  1070
        return PEP_UNKNOWN_ERROR;
Edouard@271
  1071
    }
Edouard@271
  1072
Edouard@322
  1073
    result = curl_get_ctx(&curl);
Edouard@322
  1074
    if(result != PEP_STATUS_OK){
Edouard@322
  1075
        goto unlock_curl;
Edouard@322
  1076
    }
Edouard@252
  1077
Edouard@271
  1078
    encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
Edouard@271
  1079
    if(!encoded_pattern){
Edouard@271
  1080
        result = PEP_OUT_OF_MEMORY;
Edouard@322
  1081
        goto release_curl_ctx;
Edouard@271
  1082
    }
Edouard@271
  1083
Edouard@271
  1084
    if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
Edouard@271
  1085
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1086
        goto free_encoded_pattern;
Edouard@271
  1087
    }
Edouard@174
  1088
Edouard@271
  1089
    //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
Edouard@271
  1090
    stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
Edouard@271
  1091
Edouard@271
  1092
    curl_easy_setopt(curl, CURLOPT_URL,request);
Edouard@271
  1093
Edouard@271
  1094
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
Edouard@271
  1095
Edouard@271
  1096
    answer.memory = NULL;
Edouard@271
  1097
    answer.size = 0;
Edouard@271
  1098
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
Edouard@174
  1099
Edouard@271
  1100
    curlres = curl_easy_perform(curl);
Edouard@271
  1101
    if(curlres != CURLE_OK) {
Edouard@271
  1102
        result = PEP_GET_KEY_FAILED;
Edouard@271
  1103
        goto free_request;
Edouard@271
  1104
    }
Edouard@271
  1105
Edouard@271
  1106
    if(!answer.memory || !answer.size) {
Edouard@271
  1107
        result = PEP_OUT_OF_MEMORY;
Edouard@271
  1108
        goto free_request;
Edouard@271
  1109
    }
Edouard@174
  1110
Edouard@271
  1111
    result = pgp_import_keydata(session, 
Edouard@271
  1112
                                answer.memory, 
Edouard@271
  1113
                                answer.size);
Edouard@271
  1114
Edouard@271
  1115
free_answer:
Edouard@271
  1116
    free(answer.memory);
Edouard@271
  1117
free_request:
Edouard@271
  1118
    free(request);
Edouard@271
  1119
free_encoded_pattern:
Edouard@271
  1120
    curl_free(encoded_pattern);
Edouard@322
  1121
release_curl_ctx:
Edouard@322
  1122
    curl_release_ctx(&curl);
Edouard@271
  1123
unlock_curl:
Edouard@271
  1124
    pthread_mutex_unlock(&session->ctx.curl_mutex);
Edouard@271
  1125
Edouard@271
  1126
    return result;
Edouard@174
  1127
}
Edouard@174
  1128
Edouard@277
  1129
typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
Edouard@277
  1130
Edouard@277
  1131
static PEP_STATUS find_keys_do(
Edouard@277
  1132
        const char *pattern, find_key_cb_t cb, void* cb_arg)
Edouard@254
  1133
{
Edouard@277
  1134
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@277
  1135
    size_t length;
Edouard@277
  1136
    pgp_key_t *key;
Edouard@277
  1137
Edouard@277
  1138
    PEP_STATUS result;
Edouard@277
  1139
Edouard@277
  1140
    // Try find a fingerprint in pattern
Edouard@277
  1141
    if (str_to_fpr(pattern, fpr, &length)) {
Edouard@277
  1142
Edouard@277
  1143
        // Only one fingerprint can match
Edouard@277
  1144
        if ((key = (pgp_key_t *)pgp_getkeybyfpr(
Edouard@277
  1145
                        netpgp.io,
Edouard@277
  1146
                        (pgp_keyring_t *)netpgp.pubring, 
Edouard@277
  1147
                        (const uint8_t *)fpr, length,
Edouard@277
  1148
                        NULL)) == NULL) {
Edouard@277
  1149
Edouard@277
  1150
            return PEP_KEY_NOT_FOUND;
Edouard@277
  1151
        }
Edouard@277
  1152
Edouard@277
  1153
        result = cb(cb_arg, key);
Edouard@277
  1154
Edouard@277
  1155
    } else {
Edouard@277
  1156
        // Search by name for pattern. Can match many.
Edouard@277
  1157
        unsigned from = 0;
Edouard@277
  1158
        result = PEP_KEY_NOT_FOUND;
Edouard@277
  1159
        while((key = (pgp_key_t *)pgp_getnextkeybyname(
Edouard@277
  1160
                        netpgp.io,
Edouard@277
  1161
                        (pgp_keyring_t *)netpgp.pubring, 
Edouard@277
  1162
			            (const char *)pattern,
Edouard@277
  1163
                        &from)) != NULL) {
Edouard@277
  1164
Edouard@277
  1165
            result = cb(cb_arg, key);
Edouard@277
  1166
            if (result != PEP_STATUS_OK)
Edouard@277
  1167
                break;
Edouard@277
  1168
Edouard@277
  1169
            from++;
Edouard@277
  1170
        }
Edouard@277
  1171
    }
Edouard@277
  1172
Edouard@277
  1173
    return result;
Edouard@277
  1174
}
Edouard@277
  1175
Edouard@277
  1176
static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
Edouard@277
  1177
{
Edouard@277
  1178
    stringlist_t **keylist = arg;
Edouard@254
  1179
    char *newfprstr = NULL;
Edouard@254
  1180
Edouard@254
  1181
    fpr_to_str(&newfprstr,
Edouard@313
  1182
               key->pubkeyfpr.fingerprint,
Edouard@313
  1183
               key->pubkeyfpr.length);
Edouard@254
  1184
Edouard@254
  1185
    if (newfprstr == NULL) {
Edouard@254
  1186
        return PEP_OUT_OF_MEMORY;
Edouard@254
  1187
    } else { 
Edouard@254
  1188
Edouard@254
  1189
        *keylist = stringlist_add(*keylist, newfprstr);
Edouard@254
  1190
        if (*keylist == NULL) {
Edouard@254
  1191
            free(newfprstr);
Edouard@254
  1192
            return PEP_OUT_OF_MEMORY;
Edouard@254
  1193
        }
Edouard@254
  1194
    }
Edouard@254
  1195
    return PEP_STATUS_OK;
Edouard@254
  1196
}
Edouard@254
  1197
Edouard@174
  1198
PEP_STATUS pgp_find_keys(
Edouard@174
  1199
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
Edouard@174
  1200
    )
Edouard@174
  1201
{
Edouard@254
  1202
    stringlist_t *_keylist, *_k;
Edouard@254
  1203
Edouard@254
  1204
    PEP_STATUS result;
Edouard@174
  1205
Edouard@174
  1206
    assert(session);
Edouard@174
  1207
    assert(pattern);
Edouard@174
  1208
    assert(keylist);
Edouard@174
  1209
Edouard@254
  1210
    if (!session || !pattern || !keylist )
Edouard@254
  1211
        return PEP_UNKNOWN_ERROR;
Edouard@174
  1212
Edouard@263
  1213
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@174
  1214
        return PEP_UNKNOWN_ERROR;
Edouard@254
  1215
    }
Edouard@254
  1216
Edouard@254
  1217
    *keylist = NULL;
Edouard@254
  1218
    _keylist = new_stringlist(NULL);
Edouard@254
  1219
    if (_k == NULL) {
Edouard@254
  1220
        result = PEP_OUT_OF_MEMORY;
Edouard@254
  1221
        goto unlock_netpgp;
Edouard@254
  1222
    }
Edouard@254
  1223
    _k = _keylist;
Edouard@254
  1224
Edouard@277
  1225
    result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
Edouard@254
  1226
Edouard@254
  1227
    if (result == PEP_STATUS_OK) {
Edouard@254
  1228
        *keylist = _keylist;
Edouard@254
  1229
        // Transfer ownership, no free
Edouard@254
  1230
        goto unlock_netpgp;
Edouard@254
  1231
    }
Edouard@254
  1232
Edouard@254
  1233
free_keylist:
Edouard@254
  1234
    free_stringlist(_keylist);
Edouard@254
  1235
Edouard@254
  1236
unlock_netpgp:
Edouard@254
  1237
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@254
  1238
Edouard@254
  1239
    return result;
Edouard@174
  1240
}
Edouard@174
  1241
Edouard@321
  1242
#define HKP_REQ_PREFIX "keytext="
Edouard@321
  1243
#define HKP_REQ_PREFIX_LEN 8
Edouard@321
  1244
Edouard@277
  1245
static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
Edouard@277
  1246
{
Edouard@318
  1247
    char *buffer = NULL;
Edouard@318
  1248
    size_t buflen = 0;
Edouard@318
  1249
    PEP_STATUS result;
Edouard@318
  1250
    stringlist_t *encoded_keys;
Edouard@318
  1251
    encoded_keys = (stringlist_t*)arg;
Edouard@277
  1252
Edouard@318
  1253
    result = _export_keydata(key, &buffer, &buflen);
Edouard@318
  1254
    
Edouard@318
  1255
    if(result == PEP_STATUS_OK){
Edouard@318
  1256
        char *encoded_key;
Edouard@321
  1257
        char *request;
Edouard@321
  1258
        size_t encoded_key_len;
Edouard@321
  1259
Edouard@318
  1260
        encoded_key = curl_escape(buffer, buflen);
Edouard@318
  1261
        if(!encoded_key){
Edouard@321
  1262
            result = PEP_OUT_OF_MEMORY;
Edouard@321
  1263
            goto free_buffer;
Edouard@318
  1264
        }
Edouard@321
  1265
        encoded_key_len = strlen(encoded_key);
Edouard@321
  1266
Edouard@321
  1267
        request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
Edouard@321
  1268
        if(!request){
Edouard@321
  1269
            result = PEP_OUT_OF_MEMORY;
Edouard@321
  1270
            goto free_encoded_key;
Edouard@321
  1271
        }
Edouard@321
  1272
        
Edouard@321
  1273
        memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
Edouard@321
  1274
        memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
Edouard@321
  1275
        request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
Edouard@321
  1276
Edouard@321
  1277
        if(!stringlist_add(encoded_keys, request)){
Edouard@318
  1278
            result = PEP_OUT_OF_MEMORY;
Edouard@318
  1279
        }
Edouard@321
  1280
Edouard@321
  1281
        free(request);
Edouard@321
  1282
Edouard@321
  1283
free_encoded_key:
Edouard@318
  1284
        curl_free(encoded_key);
Edouard@321
  1285
Edouard@321
  1286
free_buffer:        
Edouard@321
  1287
        free(buffer);
Edouard@318
  1288
    }
Edouard@277
  1289
Edouard@318
  1290
    return result;
Edouard@277
  1291
}
Edouard@277
  1292
Edouard@174
  1293
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
Edouard@174
  1294
{
Edouard@321
  1295
    static const char *ks_cmd = HKP_SERVER "/pks/add";
Edouard@318
  1296
Edouard@318
  1297
    stringlist_t *encoded_keys;
Edouard@318
  1298
    const stringlist_t *post;
Edouard@277
  1299
Edouard@277
  1300
    PEP_STATUS result;
Edouard@277
  1301
Edouard@322
  1302
    CURL *curl;
Edouard@322
  1303
Edouard@174
  1304
    assert(session);
Edouard@174
  1305
    assert(pattern);
Edouard@174
  1306
Edouard@277
  1307
    if (!session || !pattern )
Edouard@277
  1308
        return PEP_UNKNOWN_ERROR;
Edouard@277
  1309
Edouard@318
  1310
    encoded_keys = new_stringlist(NULL);
Edouard@318
  1311
    assert(encoded_keys);
Edouard@318
  1312
    if (encoded_keys == NULL) {
Edouard@318
  1313
        return PEP_OUT_OF_MEMORY;
Edouard@318
  1314
    }
Edouard@318
  1315
Edouard@277
  1316
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@322
  1317
        result = PEP_UNKNOWN_ERROR;
Edouard@322
  1318
        goto free_encoded_keys;
Edouard@277
  1319
    }
Edouard@174
  1320
Edouard@318
  1321
    result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
Edouard@277
  1322
Edouard@277
  1323
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@277
  1324
Edouard@322
  1325
    if(result != PEP_STATUS_OK){
Edouard@322
  1326
        goto free_encoded_keys;
Edouard@322
  1327
    }
Edouard@322
  1328
Edouard@318
  1329
    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
Edouard@322
  1330
        result = PEP_UNKNOWN_ERROR;
Edouard@322
  1331
        goto free_encoded_keys;
Edouard@322
  1332
    }
Edouard@322
  1333
Edouard@322
  1334
    result = curl_get_ctx(&curl);
Edouard@322
  1335
    if(result != PEP_STATUS_OK){
Edouard@322
  1336
        goto unlock_curl;
Edouard@318
  1337
    }
Edouard@318
  1338
Edouard@318
  1339
    if(result == PEP_STATUS_OK){
Edouard@318
  1340
        CURLcode curlres;
Edouard@318
  1341
Edouard@318
  1342
        for (post = encoded_keys; post != NULL; post = post->next) {
Edouard@318
  1343
            assert(post->value);
Edouard@318
  1344
Edouard@318
  1345
            curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
Edouard@318
  1346
            curl_easy_setopt(curl, CURLOPT_POST, 1L);
Edouard@318
  1347
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
Edouard@318
  1348
            curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
Edouard@318
  1349
Edouard@323
  1350
            // Uncomment if debugging
Edouard@323
  1351
            // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
Edouard@318
  1352
Edouard@318
  1353
            curlres = curl_easy_perform(curl);
Edouard@318
  1354
Edouard@318
  1355
            if(curlres != CURLE_OK) {
Edouard@318
  1356
Edouard@318
  1357
                result = PEP_CANNOT_SEND_KEY;
Edouard@322
  1358
                goto release_curl_ctx;
Edouard@318
  1359
            }
Edouard@318
  1360
        }
Edouard@318
  1361
    }
Edouard@318
  1362
Edouard@322
  1363
release_curl_ctx:
Edouard@322
  1364
    curl_release_ctx(&curl);
Edouard@322
  1365
unlock_curl:
Edouard@322
  1366
    pthread_mutex_unlock(&session->ctx.curl_mutex);
Edouard@318
  1367
free_encoded_keys:
Edouard@318
  1368
    free_stringlist(encoded_keys);
Edouard@318
  1369
Edouard@277
  1370
    return result;
Edouard@174
  1371
}
Edouard@174
  1372
Edouard@174
  1373
Edouard@174
  1374
PEP_STATUS pgp_get_key_rating(
Edouard@174
  1375
    PEP_SESSION session,
Edouard@324
  1376
    const char *keyidstr,
Edouard@174
  1377
    PEP_comm_type *comm_type
Edouard@174
  1378
    )
Edouard@174
  1379
{
Edouard@324
  1380
    const pgp_key_t *key;
Edouard@324
  1381
    uint8_t keyid[PGP_KEY_ID_SIZE];
Edouard@324
  1382
    unsigned from = 0;
Edouard@324
  1383
Edouard@174
  1384
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@174
  1385
Edouard@174
  1386
    assert(session);
Edouard@324
  1387
    assert(keyidstr);
Edouard@174
  1388
    assert(comm_type);
Edouard@174
  1389
Edouard@324
  1390
    if (!session || !keyidstr || !comm_type )
Edouard@324
  1391
        return PEP_UNKNOWN_ERROR;
Edouard@324
  1392
Edouard@324
  1393
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@324
  1394
        return PEP_UNKNOWN_ERROR;
Edouard@324
  1395
    }
Edouard@324
  1396
Edouard@324
  1397
    if(!str_to_id(keyid, keyidstr))
Edouard@324
  1398
    {
Edouard@324
  1399
        status = PEP_ILLEGAL_VALUE;
Edouard@324
  1400
        goto unlock_netpgp;
Edouard@324
  1401
    }
Edouard@174
  1402
Edouard@324
  1403
    key = pgp_getkeybyid(netpgp.io, netpgp.pubring, 
Edouard@324
  1404
             keyid, &from, NULL, NULL, 
Edouard@324
  1405
             0, 0); /* accept revoked and expired */
Edouard@174
  1406
Edouard@324
  1407
    if(key == NULL)
Edouard@324
  1408
    {
Edouard@324
  1409
        status = PEP_KEY_NOT_FOUND;
Edouard@324
  1410
        goto unlock_netpgp;
Edouard@324
  1411
    }
Edouard@324
  1412
Edouard@324
  1413
    switch(pgp_key_get_rating(key)){
Edouard@324
  1414
	case PGP_VALID:
Edouard@174
  1415
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
Edouard@174
  1416
        break;
Edouard@324
  1417
    case PGP_WEAK:
Edouard@324
  1418
        *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
Edouard@324
  1419
        break;
Edouard@324
  1420
    case PGP_TOOSHORT:
Edouard@324
  1421
        *comm_type = PEP_ct_key_too_short;
Edouard@324
  1422
        break;
Edouard@324
  1423
	case PGP_INVALID:
Edouard@324
  1424
        *comm_type = PEP_ct_key_b0rken;
Edouard@324
  1425
        break;
Edouard@324
  1426
	case PGP_EXPIRED:
Edouard@324
  1427
        *comm_type = PEP_ct_key_expired;
Edouard@324
  1428
        break;
Edouard@324
  1429
    case PGP_REVOKED:
Edouard@324
  1430
        *comm_type = PEP_ct_key_revoked;
Edouard@174
  1431
        break;
Edouard@174
  1432
    default:
Edouard@174
  1433
        *comm_type = PEP_ct_unknown;
Edouard@324
  1434
        break;
Edouard@174
  1435
    }
Edouard@174
  1436
Edouard@324
  1437
unlock_netpgp:
Edouard@324
  1438
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@174
  1439
Edouard@174
  1440
    return status;
Edouard@174
  1441
}
Edouard@210
  1442
Edouard@210
  1443
PEP_STATUS pgp_renew_key(
Edouard@210
  1444
        PEP_SESSION session,
Edouard@329
  1445
        const char *keyidstr,
Edouard@210
  1446
        const timestamp *ts
Edouard@210
  1447
    )
Edouard@210
  1448
{
Edouard@329
  1449
    pgp_key_t *pkey;
Edouard@329
  1450
    pgp_key_t *skey;
Edouard@329
  1451
    uint8_t keyid[PGP_KEY_ID_SIZE];
Edouard@329
  1452
    unsigned from = 0;
Edouard@329
  1453
    uint64_t duration;
Edouard@329
  1454
    uint8_t *primid;
Edouard@329
  1455
Edouard@210
  1456
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
  1457
Edouard@210
  1458
    assert(session);
Edouard@329
  1459
    assert(keyidstr);
Edouard@329
  1460
Edouard@329
  1461
    if (!session || !keyidstr )
Edouard@329
  1462
        return PEP_UNKNOWN_ERROR;
Edouard@329
  1463
Edouard@329
  1464
    if(ts)
Edouard@329
  1465
    {
Edouard@329
  1466
        time_t    now, when;
Edouard@329
  1467
        now = time(NULL);
Edouard@329
  1468
        when = mktime((struct tm*)ts);
Edouard@329
  1469
        if(now && when && when > now){
Edouard@329
  1470
            duration = (uint64_t)(when - now);
Edouard@329
  1471
        }else{
Edouard@329
  1472
            return PEP_ILLEGAL_VALUE;
Edouard@329
  1473
        }
Edouard@329
  1474
    }else{
Edouard@329
  1475
        /* Default 1 year from now */
Edouard@329
  1476
        duration = 365*24*3600;
Edouard@329
  1477
    }
Edouard@329
  1478
Edouard@329
  1479
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@329
  1480
        return PEP_UNKNOWN_ERROR;
Edouard@329
  1481
    }
Edouard@210
  1482
Edouard@329
  1483
    if(!str_to_id(keyid, keyidstr))
Edouard@329
  1484
    {
Edouard@329
  1485
        status = PEP_ILLEGAL_VALUE;
Edouard@329
  1486
        goto unlock_netpgp;
Edouard@329
  1487
    }
Edouard@329
  1488
Edouard@329
  1489
    pkey = (pgp_key_t*)pgp_getkeybyid(netpgp.io, netpgp.pubring, 
Edouard@329
  1490
             keyid, &from, NULL, NULL, 
Edouard@329
  1491
             1, 0); /* reject revoked, accept expired */
Edouard@329
  1492
Edouard@329
  1493
    if(pkey == NULL)
Edouard@329
  1494
    {
Edouard@329
  1495
        status = PEP_KEY_NOT_FOUND;
Edouard@329
  1496
        goto unlock_netpgp;
Edouard@329
  1497
    }
Edouard@329
  1498
Edouard@329
  1499
    from = 0;
Edouard@329
  1500
    skey = (pgp_key_t*)pgp_getkeybyid(netpgp.io, netpgp.secring, 
Edouard@329
  1501
             keyid, &from, NULL, NULL, 
Edouard@329
  1502
             1, 0); /* reject revoked, accept expired */
Edouard@329
  1503
Edouard@329
  1504
    if(skey == NULL)
Edouard@329
  1505
    {
Edouard@329
  1506
        status = PEP_KEY_NOT_FOUND;
Edouard@329
  1507
        goto unlock_netpgp;
Edouard@329
  1508
    }
Edouard@329
  1509
Edouard@329
  1510
    if((primid = *pgp_key_get_primary_userid(skey)) == NULL)
Edouard@329
  1511
    {
Edouard@329
  1512
        status = PEP_KEY_HAS_AMBIG_NAME;
Edouard@329
  1513
        goto unlock_netpgp;
Edouard@329
  1514
    }
Edouard@210
  1515
Edouard@210
  1516
Edouard@329
  1517
    if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
Edouard@329
  1518
    {
Edouard@329
  1519
        status = PEP_CANNOT_CREATE_KEY;
Edouard@329
  1520
        goto unlock_netpgp;
Edouard@329
  1521
    }
Edouard@329
  1522
Edouard@329
  1523
unlock_netpgp:
Edouard@329
  1524
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@329
  1525
Edouard@329
  1526
    return status;
Edouard@210
  1527
}
Edouard@210
  1528
Edouard@226
  1529
PEP_STATUS pgp_revoke_key(
Edouard@226
  1530
        PEP_SESSION session,
Edouard@326
  1531
        const char *keyidstr,
Edouard@226
  1532
        const char *reason
Edouard@226
  1533
    )
Edouard@210
  1534
{
Edouard@326
  1535
    pgp_key_t *pkey;
Edouard@326
  1536
    pgp_key_t *skey;
Edouard@326
  1537
    uint8_t keyid[PGP_KEY_ID_SIZE];
Edouard@326
  1538
    unsigned from = 0;
Edouard@326
  1539
Edouard@210
  1540
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@326
  1541
Edouard@210
  1542
    assert(session);
Edouard@326
  1543
    assert(keyidstr);
Edouard@326
  1544
    assert(reason);
Edouard@210
  1545
Edouard@326
  1546
    if (!session || !keyidstr || !reason )
Edouard@210
  1547
        return PEP_UNKNOWN_ERROR;
Edouard@210
  1548
Edouard@326
  1549
    if(pthread_mutex_lock(&netpgp_mutex)){
Edouard@326
  1550
        return PEP_UNKNOWN_ERROR;
Edouard@326
  1551
    }
Edouard@326
  1552
Edouard@326
  1553
    if(!str_to_id(keyid, keyidstr))
Edouard@326
  1554
    {
Edouard@326
  1555
        status = PEP_ILLEGAL_VALUE;
Edouard@326
  1556
        goto unlock_netpgp;
Edouard@326
  1557
    }
Edouard@326
  1558
Edouard@326
  1559
    pkey = pgp_getkeybyid(netpgp.io, netpgp.pubring, 
Edouard@326
  1560
             keyid, &from, NULL, NULL, 
Edouard@326
  1561
             1, 0); /* reject (already) revoked, accept expired */
Edouard@326
  1562
Edouard@326
  1563
    if(pkey == NULL)
Edouard@326
  1564
    {
Edouard@326
  1565
        status = PEP_KEY_NOT_FOUND;
Edouard@326
  1566
        goto unlock_netpgp;
Edouard@326
  1567
    }
Edouard@326
  1568
Edouard@326
  1569
    from = 0;
Edouard@326
  1570
    skey = pgp_getkeybyid(netpgp.io, netpgp.secring, 
Edouard@326
  1571
             keyid, &from, NULL, NULL, 
Edouard@326
  1572
             1, 0); /* reject (already) revoked, accept expired */
Edouard@326
  1573
Edouard@326
  1574
    if(skey == NULL)
Edouard@326
  1575
    {
Edouard@326
  1576
        status = PEP_KEY_NOT_FOUND;
Edouard@326
  1577
        goto unlock_netpgp;
Edouard@326
  1578
    }
Edouard@326
  1579
Edouard@326
  1580
    pgp_key_revoke(skey, pkey,
Edouard@326
  1581
                   0, /* no reason code specified */
Edouard@326
  1582
                   reason);
Edouard@326
  1583
Edouard@326
  1584
unlock_netpgp:
Edouard@326
  1585
    pthread_mutex_unlock(&netpgp_mutex);
Edouard@326
  1586
Edouard@326
  1587
    return status;
Edouard@210
  1588
}
Edouard@210
  1589
Edouard@226
  1590
PEP_STATUS pgp_key_expired(
Edouard@226
  1591
        PEP_SESSION session,
Edouard@325
  1592
        const char *keyidstr,
Edouard@226
  1593
        bool *expired
Edouard@226
  1594
    )
Edouard@226
  1595
{
Edouard@226
  1596
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@325
  1597
    PEP_comm_type comm_type;
Edouard@226
  1598
Edouard@226
  1599
    assert(session);
Edouard@325
  1600
    assert(keyidstr);
Edouard@226
  1601
    assert(expired);
Edouard@226
  1602
Edouard@226
  1603
    *expired = false;
Edouard@226
  1604
Edouard@325
  1605
    status = pgp_get_key_rating(session, keyidstr, &comm_type);
Edouard@325
  1606
Edouard@226
  1607
    if (status != PEP_STATUS_OK)
Edouard@226
  1608
        return status;
Edouard@226
  1609
Edouard@325
  1610
    if (comm_type == PEP_ct_key_expired){
Edouard@325
  1611
        *expired = true;
Edouard@325
  1612
    }
Edouard@325
  1613
Edouard@226
  1614
    return PEP_STATUS_OK;
Edouard@226
  1615
}
Edouard@226
  1616