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