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