src/pgp_netpgp.c
author Edouard Tisserant
Tue, 28 Apr 2015 01:52:09 +0200
changeset 227 9321f8fb77c2
parent 226 a2079f2f7a8c
child 228 4e6728cddb3f
permissions -rw-r--r--
netpgp : added pgp_delete_keypair. Fixed broken wrong fingerprint assined to identity in generate_keypair
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@179
    14
Edouard@188
    15
#include <regex.h>
Edouard@188
    16
Edouard@185
    17
#define PEP_NETPGP_DEBUG
Edouard@185
    18
Edouard@174
    19
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
Edouard@174
    20
{
Edouard@179
    21
    netpgp_t *netpgp;
Edouard@174
    22
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@175
    23
    const char *home = NULL;
Edouard@179
    24
Edouard@179
    25
    assert(session);
Edouard@179
    26
    if(!session) return PEP_UNKNOWN_ERROR;
Edouard@179
    27
Edouard@179
    28
    netpgp = &session->ctx;
Edouard@174
    29
   
Edouard@174
    30
    if (in_first) {
Edouard@175
    31
        if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
Edouard@175
    32
            setlocale(LC_ALL, "");
Edouard@174
    33
    }
Edouard@174
    34
Edouard@185
    35
    memset(netpgp, 0x0, sizeof(session->ctx));
Edouard@174
    36
Edouard@180
    37
    // netpgp_setvar(netpgp, "max mem alloc", "4194304");
Edouard@180
    38
    netpgp_setvar(netpgp, "need seckey", "1");
Edouard@180
    39
    netpgp_setvar(netpgp, "need userid", "1");
Edouard@180
    40
Edouard@175
    41
    // NetPGP shares home with GPG
Edouard@175
    42
    home = gpg_home();
Edouard@175
    43
    if(home){
Edouard@179
    44
        netpgp_set_homedir(netpgp,(char*)home, NULL, 0);
Edouard@175
    45
    }else{
Edouard@175
    46
        status = PEP_INIT_NO_GPG_HOME;
Edouard@175
    47
        goto pep_error;
Edouard@174
    48
    }
Edouard@174
    49
Edouard@175
    50
    // pair with gpg's cert-digest-algo
Edouard@185
    51
    netpgp_setvar(netpgp, "hash", "SHA256");
Edouard@175
    52
Edouard@175
    53
    // subset of gpg's personal-cipher-preferences
Edouard@175
    54
    // here only one cipher can be selected
Edouard@225
    55
    netpgp_setvar(netpgp, "cipher", "CAST5");
Edouard@175
    56
Edouard@185
    57
    if (!netpgp_init(netpgp)) {
Edouard@175
    58
        status = PEP_INIT_NETPGP_INIT_FAILED;
Edouard@174
    59
        goto pep_error;
Edouard@174
    60
    }
Edouard@174
    61
Edouard@174
    62
    return PEP_STATUS_OK;
Edouard@174
    63
Edouard@174
    64
pep_error:
Edouard@174
    65
    pgp_release(session, in_first);
Edouard@174
    66
    return status;
Edouard@174
    67
}
Edouard@174
    68
Edouard@174
    69
void pgp_release(PEP_SESSION session, bool out_last)
Edouard@174
    70
{
Edouard@179
    71
    netpgp_t *netpgp;
Edouard@179
    72
Edouard@179
    73
    assert(session);
Edouard@179
    74
    if(!session) return;
Edouard@179
    75
Edouard@179
    76
    netpgp = &session->ctx;
Edouard@179
    77
Edouard@185
    78
    netpgp_end(netpgp);
Edouard@185
    79
    memset(netpgp, 0x0, sizeof(session->ctx));
Edouard@174
    80
Edouard@175
    81
    // out_last unused here
Edouard@174
    82
}
Edouard@174
    83
Edouard@207
    84
// return 1 if the file contains ascii-armoured text 
Edouard@207
    85
// buf MUST be \0 terminated to be checked for armour
Edouard@188
    86
static unsigned
Edouard@188
    87
_armoured(const char *buf, size_t size, const char *pattern)
Edouard@188
    88
{
Edouard@188
    89
    unsigned armoured = 0;
Edouard@188
    90
    if(buf[size]=='\0'){
Edouard@188
    91
        regex_t r;
Edouard@188
    92
        regcomp(&r, pattern, REG_EXTENDED|REG_NEWLINE|REG_NOSUB);
Edouard@188
    93
        if (regexec(&r, buf, 0, NULL, 0) == 0) {
Edouard@188
    94
            armoured = 1;
Edouard@188
    95
        }
Edouard@188
    96
        regfree(&r);
Edouard@188
    97
    }
Edouard@188
    98
    return armoured;
Edouard@188
    99
}
Edouard@188
   100
Edouard@227
   101
/* return key ID's hexdump as a string */
Edouard@227
   102
static void id_to_str(const uint8_t *userid, char *fpr)
Edouard@225
   103
{
Edouard@225
   104
    int i;
Edouard@225
   105
    static const char *hexes = "0123456789abcdef";
Edouard@225
   106
    for (i = 0; i < 8 ; i++) {
Edouard@225
   107
        fpr[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
Edouard@225
   108
        fpr[(i * 2) + 1] = hexes[userid[i] & 0xf];
Edouard@225
   109
    }
Edouard@225
   110
    fpr[8 * 2] = 0x0;
Edouard@225
   111
}
Edouard@225
   112
Edouard@185
   113
// Iterate through netpgp' reported valid signatures 
Edouard@185
   114
// fill a list of valid figerprints
Edouard@185
   115
// returns PEP_STATUS_OK if all sig reported valid
Edouard@185
   116
// error status otherwise.
Edouard@185
   117
static PEP_STATUS _validation_results(netpgp_t *netpgp, pgp_validation_t *vresult,
Edouard@185
   118
                                             stringlist_t **_keylist)
Edouard@185
   119
{
Edouard@188
   120
    time_t    now;
Edouard@188
   121
    time_t    t;
Edouard@188
   122
    char    buf[128];
Edouard@185
   123
Edouard@188
   124
    now = time(NULL);
Edouard@188
   125
    if (now < vresult->birthtime) {
Edouard@188
   126
        // signature is not valid yet
Edouard@185
   127
#ifdef PEP_NETPGP_DEBUG
Edouard@188
   128
        (void) printf(
Edouard@188
   129
            "signature not valid until %.24s\n",
Edouard@188
   130
            ctime(&vresult->birthtime));
Edouard@185
   131
#endif //PEP_NETPGP_DEBUG
Edouard@188
   132
        return PEP_UNENCRYPTED;
Edouard@188
   133
    }
Edouard@188
   134
    if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
Edouard@188
   135
        // signature has expired
Edouard@188
   136
        t = vresult->duration + vresult->birthtime;
Edouard@185
   137
#ifdef PEP_NETPGP_DEBUG
Edouard@188
   138
        (void) printf(
Edouard@188
   139
            "signature not valid after %.24s\n",
Edouard@188
   140
            ctime(&t));
Edouard@185
   141
#endif //PEP_NETPGP_DEBUG
Edouard@188
   142
        return PEP_UNENCRYPTED;
Edouard@188
   143
    }
Edouard@185
   144
    if (vresult->validc && vresult->valid_sigs &&
Edouard@185
   145
        !vresult->invalidc && !vresult->unknownc ) {
Edouard@185
   146
        unsigned    n;
Edouard@185
   147
        stringlist_t *k;
Edouard@185
   148
        // caller responsible to free
Edouard@185
   149
        *_keylist = new_stringlist(NULL);
Edouard@185
   150
        assert(*_keylist);
Edouard@185
   151
        if (*_keylist == NULL) {
Edouard@185
   152
            return PEP_OUT_OF_MEMORY;
Edouard@185
   153
        }
Edouard@185
   154
        k = *_keylist;
Edouard@185
   155
        for (n = 0; n < vresult->validc; ++n) {
Edouard@185
   156
            char id[MAX_ID_LENGTH + 1];
Edouard@185
   157
            const uint8_t *userid = vresult->valid_sigs[n].signer_id;
Edouard@185
   158
Edouard@185
   159
#ifdef PEP_NETPGP_DEBUG
Edouard@185
   160
            const pgp_key_t *key;
Edouard@185
   161
            pgp_pubkey_t *sigkey;
Edouard@188
   162
            unsigned from = 0;
Edouard@185
   163
            key = pgp_getkeybyid(netpgp->io, netpgp->pubring,
Edouard@185
   164
                (const uint8_t *) vresult->valid_sigs[n].signer_id,
Edouard@185
   165
                &from, &sigkey);
Edouard@185
   166
            pgp_print_keydata(netpgp->io, netpgp->pubring, key, "valid signature ", &key->key.pubkey, 0);
Edouard@185
   167
#endif //PEP_NETPGP_DEBUG
Edouard@185
   168
Edouard@227
   169
            id_to_str(userid, id);
Edouard@185
   170
Edouard@185
   171
            k = stringlist_add(k, id);
Edouard@185
   172
            if(!k){
Edouard@185
   173
                free_stringlist(*_keylist);
Edouard@185
   174
                return PEP_OUT_OF_MEMORY;
Edouard@185
   175
            }
Edouard@185
   176
        }
Edouard@185
   177
        return PEP_STATUS_OK;
Edouard@185
   178
    }
Edouard@185
   179
    if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
Edouard@185
   180
        // No signatures found - is this memory signed?
Edouard@185
   181
        return PEP_VERIFY_NO_KEY; 
Edouard@185
   182
    } 
Edouard@185
   183
    
Edouard@185
   184
    if (vresult->invalidc) {
Edouard@185
   185
        // some invalid signatures
Edouard@185
   186
Edouard@185
   187
#ifdef PEP_NETPGP_DEBUG
Edouard@185
   188
        unsigned    n;
Edouard@185
   189
        for (n = 0; n < vresult->invalidc; ++n) {
Edouard@185
   190
            const pgp_key_t *key;
Edouard@185
   191
            pgp_pubkey_t *sigkey;
Edouard@185
   192
            unsigned from = 0;
Edouard@185
   193
            key = pgp_getkeybyid(netpgp->io, netpgp->pubring,
Edouard@185
   194
                (const uint8_t *) vresult->invalid_sigs[n].signer_id,
Edouard@185
   195
                &from, &sigkey);
Edouard@185
   196
            pgp_print_keydata(netpgp->io, netpgp->pubring, key, "invalid signature ", &key->key.pubkey, 0);
Edouard@188
   197
            if (sigkey->duration != 0 && now > sigkey->birthtime + sigkey->duration) {
Edouard@185
   198
                printf("EXPIRED !\n");
Edouard@185
   199
            }
Edouard@185
   200
        }
Edouard@185
   201
#endif //PEP_NETPGP_DEBUG
Edouard@185
   202
Edouard@185
   203
        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@185
   204
    }
Edouard@185
   205
    
Edouard@185
   206
    // only unknown sigs
Edouard@185
   207
    return PEP_DECRYPT_WRONG_FORMAT;
Edouard@185
   208
}
Edouard@185
   209
Edouard@207
   210
#define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----\\s*$"
Edouard@174
   211
PEP_STATUS pgp_decrypt_and_verify(
Edouard@174
   212
    PEP_SESSION session, const char *ctext, size_t csize,
Edouard@174
   213
    char **ptext, size_t *psize, stringlist_t **keylist
Edouard@174
   214
    )
Edouard@174
   215
{
Edouard@179
   216
    netpgp_t *netpgp;
Edouard@185
   217
    pgp_memory_t *mem;
Edouard@185
   218
    pgp_memory_t *cat;
Edouard@185
   219
    pgp_validation_t *vresult;
Edouard@180
   220
    char *_ptext = NULL;
Edouard@180
   221
    size_t _psize = 0;
Edouard@185
   222
    int ret;
Edouard@179
   223
Edouard@174
   224
    PEP_STATUS result;
Edouard@174
   225
    stringlist_t *_keylist = NULL;
Edouard@174
   226
    int i_key = 0;
Edouard@174
   227
Edouard@174
   228
    assert(session);
Edouard@174
   229
    assert(ctext);
Edouard@174
   230
    assert(csize);
Edouard@174
   231
    assert(ptext);
Edouard@174
   232
    assert(psize);
Edouard@174
   233
    assert(keylist);
Edouard@174
   234
Edouard@179
   235
    if(!session || !ctext || !csize || !ptext || !psize || !keylist) 
Edouard@179
   236
        return PEP_UNKNOWN_ERROR;
Edouard@179
   237
Edouard@179
   238
    netpgp = &session->ctx;
Edouard@179
   239
Edouard@174
   240
    *ptext = NULL;
Edouard@174
   241
    *psize = 0;
Edouard@174
   242
    *keylist = NULL;
Edouard@174
   243
Edouard@183
   244
    vresult = malloc(sizeof(pgp_validation_t));
Edouard@185
   245
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@182
   246
Edouard@183
   247
    mem = pgp_decrypt_and_validate_buf(netpgp->io, vresult, ctext, csize,
Edouard@179
   248
                netpgp->secring, netpgp->pubring,
Edouard@188
   249
                _armoured(ctext, csize, ARMOR_HEAD),
Edouard@179
   250
                0 /* sshkeys */,
Edouard@180
   251
                NULL, -1, NULL  /* pass fp,attempts,cb */);
Edouard@179
   252
    if (mem == NULL) {
Edouard@179
   253
        return PEP_OUT_OF_MEMORY;
Edouard@179
   254
    }
Edouard@179
   255
Edouard@185
   256
    _psize = pgp_mem_len(mem);
Edouard@182
   257
    if (_psize){
Edouard@182
   258
        if ((_ptext = calloc(1, _psize)) == NULL) {
Edouard@183
   259
            result = PEP_OUT_OF_MEMORY;
Edouard@183
   260
            goto free_pgp;
Edouard@182
   261
        }
Edouard@185
   262
        memcpy(_ptext, pgp_mem_data(mem), _psize);
Edouard@182
   263
        result = PEP_DECRYPTED;
Edouard@182
   264
    }else{
Edouard@183
   265
        result = PEP_DECRYPT_NO_KEY;
Edouard@183
   266
        goto free_pgp;
Edouard@182
   267
    }
Edouard@180
   268
Edouard@185
   269
    if (result == PEP_DECRYPTED) {
Edouard@185
   270
        result = _validation_results(netpgp, vresult, &_keylist);
Edouard@185
   271
        if (result != PEP_STATUS_OK) {
Edouard@185
   272
            goto free_ptext;
Edouard@183
   273
        }
Edouard@180
   274
        result = PEP_DECRYPTED_AND_VERIFIED;
Edouard@180
   275
    }
Edouard@174
   276
Edouard@180
   277
    if (result == PEP_DECRYPTED_AND_VERIFIED
Edouard@180
   278
        || result == PEP_DECRYPTED) {
Edouard@180
   279
        *ptext = _ptext;
Edouard@180
   280
        *psize = _psize;
Edouard@180
   281
        (*ptext)[*psize] = 0; // safeguard for naive users
Edouard@185
   282
        if (result == PEP_DECRYPTED_AND_VERIFIED) {
Edouard@185
   283
            *keylist = _keylist;
Edouard@185
   284
        }
Edouard@183
   285
Edouard@183
   286
        /* _ptext and _keylist ownership transfer, don't free */
Edouard@183
   287
        goto free_pgp;
Edouard@180
   288
    }
Edouard@183
   289
Edouard@183
   290
free_keylist:
Edouard@183
   291
    free_stringlist(_keylist);
Edouard@183
   292
Edouard@183
   293
free_ptext:
Edouard@183
   294
    free(_ptext);
Edouard@183
   295
Edouard@183
   296
free_pgp:
Edouard@185
   297
    pgp_memory_free(mem);
Edouard@183
   298
    pgp_validate_result_free(vresult);
Edouard@183
   299
Edouard@174
   300
    return result;
Edouard@174
   301
}
Edouard@174
   302
Edouard@207
   303
#define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----\\s*$"
Edouard@174
   304
PEP_STATUS pgp_verify_text(
Edouard@174
   305
    PEP_SESSION session, const char *text, size_t size,
Edouard@174
   306
    const char *signature, size_t sig_size, stringlist_t **keylist
Edouard@174
   307
    )
Edouard@174
   308
{
Edouard@185
   309
    netpgp_t *netpgp;
Edouard@185
   310
    pgp_memory_t *signedmem;
Edouard@185
   311
    pgp_memory_t *sig;
Edouard@185
   312
    pgp_validation_t *vresult;
Edouard@185
   313
Edouard@174
   314
    PEP_STATUS result;
Edouard@174
   315
    stringlist_t *_keylist;
Edouard@174
   316
Edouard@174
   317
    assert(session);
Edouard@174
   318
    assert(text);
Edouard@174
   319
    assert(size);
Edouard@174
   320
    assert(signature);
Edouard@174
   321
    assert(sig_size);
Edouard@174
   322
    assert(keylist);
Edouard@174
   323
Edouard@185
   324
    if(!session || !text || !size || !signature || !sig_size || !keylist) 
Edouard@185
   325
        return PEP_UNKNOWN_ERROR;
Edouard@185
   326
Edouard@185
   327
    netpgp = &session->ctx;
Edouard@185
   328
Edouard@174
   329
    *keylist = NULL;
Edouard@185
   330
Edouard@185
   331
    vresult = malloc(sizeof(pgp_validation_t));
Edouard@185
   332
    memset(vresult, 0x0, sizeof(pgp_validation_t));
Edouard@185
   333
Edouard@185
   334
    signedmem = pgp_memory_new();
Edouard@185
   335
    if (signedmem == NULL) {
Edouard@185
   336
        return PEP_OUT_OF_MEMORY;
Edouard@185
   337
    }
Edouard@185
   338
    pgp_memory_add(signedmem, (const uint8_t*)text, size);
Edouard@185
   339
Edouard@185
   340
    sig = pgp_memory_new();
Edouard@185
   341
    if (sig == NULL) {
Edouard@185
   342
        pgp_memory_free(signedmem);
Edouard@185
   343
        return PEP_OUT_OF_MEMORY;
Edouard@185
   344
    }
Edouard@185
   345
    pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
Edouard@185
   346
Edouard@185
   347
    pgp_validate_mem_detached(netpgp->io, vresult, sig,
Edouard@185
   348
                NULL,/* output */
Edouard@207
   349
                _armoured(signature, sig_size, ARMOR_SIG_HEAD),
Edouard@185
   350
                netpgp->pubring,
Edouard@185
   351
                signedmem);
Edouard@185
   352
Edouard@185
   353
    result = _validation_results(netpgp, vresult, &_keylist);
Edouard@185
   354
    if (result != PEP_STATUS_OK) {
Edouard@185
   355
        goto free_pgp;
Edouard@185
   356
    }else{
Edouard@185
   357
        result = PEP_VERIFIED;
Edouard@185
   358
    }
Edouard@185
   359
Edouard@185
   360
    if (result == PEP_VERIFIED) {
Edouard@185
   361
        /* TODO : check trust level */
Edouard@185
   362
        result = PEP_VERIFIED_AND_TRUSTED;
Edouard@185
   363
    }
Edouard@185
   364
Edouard@185
   365
    if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
Edouard@185
   366
        *keylist = _keylist;
Edouard@185
   367
Edouard@185
   368
        /* _keylist ownership transfer, don't free */
Edouard@185
   369
        goto free_pgp;
Edouard@185
   370
    }
Edouard@185
   371
Edouard@185
   372
free_keylist:
Edouard@185
   373
    free_stringlist(_keylist);
Edouard@185
   374
Edouard@185
   375
free_pgp:
Edouard@187
   376
    // free done by pgp_validate_mem_detached
Edouard@187
   377
    // pgp_memory_free(sig);
Edouard@187
   378
    // pgp_memory_free(signedmem);
Edouard@185
   379
    pgp_validate_result_free(vresult);
Edouard@185
   380
Edouard@185
   381
    return result;
Edouard@174
   382
}
Edouard@174
   383
Edouard@174
   384
PEP_STATUS pgp_encrypt_and_sign(
Edouard@174
   385
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
Edouard@174
   386
    size_t psize, char **ctext, size_t *csize
Edouard@174
   387
    )
Edouard@174
   388
{
Edouard@207
   389
    netpgp_t *netpgp;
Edouard@207
   390
    const pgp_key_t *keypair;
Edouard@207
   391
    pgp_seckey_t *seckey;
Edouard@209
   392
    pgp_memory_t *signedmem;
Edouard@209
   393
    pgp_memory_t *cmem;
Edouard@207
   394
    const char *userid;
Edouard@207
   395
    const char *hashalg;
Edouard@209
   396
    pgp_keyring_t *rcpts;
Edouard@207
   397
Edouard@174
   398
    PEP_STATUS result;
Edouard@174
   399
    const stringlist_t *_keylist;
Edouard@174
   400
Edouard@174
   401
    assert(session);
Edouard@174
   402
    assert(keylist);
Edouard@174
   403
    assert(ptext);
Edouard@174
   404
    assert(psize);
Edouard@174
   405
    assert(ctext);
Edouard@174
   406
    assert(csize);
Edouard@174
   407
Edouard@207
   408
    if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
Edouard@207
   409
        return PEP_UNKNOWN_ERROR;
Edouard@207
   410
Edouard@208
   411
    netpgp = &session->ctx;
Edouard@208
   412
Edouard@174
   413
    *ctext = NULL;
Edouard@174
   414
    *csize = 0;
Edouard@174
   415
Edouard@207
   416
    // Get signing details from netpgp
Edouard@207
   417
    if ((userid = netpgp_getvar(netpgp, "userid")) == NULL || 
Edouard@207
   418
        (keypair = pgp_getkeybyname(netpgp->io, netpgp->secring, userid)) == NULL ||
Edouard@207
   419
        (seckey = pgp_decrypt_seckey(keypair, NULL /*passfp*/)) == NULL) {
Edouard@207
   420
        return PEP_UNKNOWN_ERROR;
Edouard@207
   421
    }
Edouard@209
   422
Edouard@207
   423
    hashalg = netpgp_getvar(netpgp, "hash");
Edouard@209
   424
    // netpgp (l)imitation - XXX why ? 
Edouard@207
   425
    if (seckey->pubkey.alg == PGP_PKA_DSA) {
Edouard@209
   426
        hashalg = "sha1";
Edouard@207
   427
    }
Edouard@207
   428
Edouard@207
   429
    // Sign data
Edouard@207
   430
    signedmem = pgp_sign_buf(netpgp->io, ptext, psize, seckey,
Edouard@209
   431
                time(NULL), /* birthtime */
Edouard@209
   432
                0 /* duration */,
Edouard@209
   433
                hashalg, 
Edouard@207
   434
                0 /* armored */,
Edouard@207
   435
                0 /* cleartext */);
Edouard@207
   436
Edouard@207
   437
    pgp_forget(seckey, (unsigned)sizeof(*seckey));
Edouard@207
   438
Edouard@207
   439
    if (!signedmem) {
Edouard@207
   440
        return PEP_UNENCRYPTED;
Edouard@207
   441
    }
Edouard@207
   442
Edouard@207
   443
    // Encrypt signed data
Edouard@209
   444
    if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
Edouard@209
   445
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   446
        goto free_signedmem;
Edouard@209
   447
    }
Edouard@209
   448
    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
Edouard@174
   449
        assert(_keylist->value);
Edouard@209
   450
        // get key from netpgp's pubring
Edouard@209
   451
        const pgp_key_t *key;
Edouard@209
   452
        key = pgp_getkeybyname(netpgp->io,
Edouard@209
   453
                               netpgp->pubring,
Edouard@209
   454
                               _keylist->value);
Edouard@209
   455
Edouard@209
   456
        if(key == NULL){
Edouard@209
   457
            result = PEP_KEY_NOT_FOUND;
Edouard@209
   458
            goto free_rcpts;
Edouard@209
   459
        }
Edouard@209
   460
#ifdef PEP_NETPGP_DEBUG
Edouard@209
   461
        pgp_print_keydata(netpgp->io, netpgp->pubring, key,
Edouard@209
   462
                          "recipient pubkey ", &key->key.pubkey, 0);
Edouard@209
   463
#endif //PEP_NETPGP_DEBUG
Edouard@209
   464
Edouard@209
   465
        // add key to recipients/signers
Edouard@209
   466
        pgp_keyring_add(rcpts, key);
Edouard@209
   467
        if(rcpts->keys == NULL){
Edouard@209
   468
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   469
            goto free_signedmem;
Edouard@209
   470
        }
Edouard@174
   471
    }
Edouard@174
   472
Edouard@209
   473
    cmem = pgp_encrypt_buf(netpgp->io, pgp_mem_data(signedmem),
Edouard@209
   474
            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
Edouard@209
   475
            netpgp_getvar(netpgp, "cipher"), 
Edouard@209
   476
            1 /* takes raw OpenPGP message */);
Edouard@209
   477
Edouard@209
   478
    if (cmem == NULL) {
Edouard@209
   479
        result = PEP_OUT_OF_MEMORY;
Edouard@209
   480
        goto free_signedmem;
Edouard@209
   481
    }else{
Edouard@209
   482
Edouard@209
   483
        char *_buffer = NULL;
Edouard@209
   484
        size_t length = pgp_mem_len(cmem);
Edouard@209
   485
        assert(length != -1);
Edouard@174
   486
Edouard@209
   487
        // Allocate transferable buffer
Edouard@209
   488
        _buffer = malloc(length + 1);
Edouard@209
   489
        assert(_buffer);
Edouard@209
   490
        if (_buffer == NULL) {
Edouard@209
   491
            result = PEP_OUT_OF_MEMORY;
Edouard@209
   492
            goto free_cmem;
Edouard@209
   493
        }
Edouard@209
   494
Edouard@209
   495
        memcpy(_buffer, pgp_mem_data(cmem), length);
Edouard@209
   496
Edouard@209
   497
        *ctext = _buffer;
Edouard@209
   498
        *csize = length;
Edouard@209
   499
        (*ctext)[*csize] = 0; // safeguard for naive users
Edouard@209
   500
        result = PEP_STATUS_OK;
Edouard@174
   501
    }
Edouard@174
   502
Edouard@209
   503
free_cmem :
Edouard@209
   504
    pgp_memory_free(cmem);
Edouard@209
   505
free_rcpts :
Edouard@209
   506
    pgp_keyring_free(rcpts);
Edouard@209
   507
free_signedmem :
Edouard@209
   508
    pgp_memory_free(signedmem);
Edouard@175
   509
Edouard@174
   510
    return result;
Edouard@174
   511
}
Edouard@174
   512
Edouard@227
   513
/* return the hexdump as a string */
Edouard@227
   514
static unsigned
Edouard@227
   515
fpr_to_str (char **str, const uint8_t *fpr, size_t length)
Edouard@227
   516
{
Edouard@227
   517
	unsigned i;
Edouard@227
   518
	int	n;
Edouard@227
   519
Edouard@227
   520
    /* 5 char per byte (hexes + space) tuple -1 space at the end + null */
Edouard@227
   521
    *str = malloc((length / 2) * 5 - 1 + 1);
Edouard@227
   522
Edouard@227
   523
    if(*str == NULL)
Edouard@227
   524
        return 0;
Edouard@227
   525
Edouard@227
   526
	for (n = 0, i = 0 ; i < length - 1; i += 2) {
Edouard@227
   527
		n += snprintf(&((*str)[n]), 6, "%02x%02x ", *fpr++, *fpr++);
Edouard@227
   528
	}
Edouard@227
   529
    snprintf(&((*str)[n]), 5, "%02x%02x", *fpr++, *fpr++);
Edouard@227
   530
Edouard@227
   531
	return 1;
Edouard@227
   532
}
Edouard@227
   533
Edouard@227
   534
static unsigned
Edouard@227
   535
str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
Edouard@227
   536
{
Edouard@227
   537
    unsigned i,j;
Edouard@227
   538
Edouard@227
   539
    *length = 0;
Edouard@227
   540
Edouard@227
   541
    while(*str && *length < PGP_FINGERPRINT_SIZE){
Edouard@227
   542
        while (*str == ' ') str++;
Edouard@227
   543
        for (j = 0; j < 2; j++) {
Edouard@227
   544
            uint8_t *byte = &fpr[*length];
Edouard@227
   545
            for (i = 0; i < 2; i++) {
Edouard@227
   546
                if (i > 0)
Edouard@227
   547
                    *byte *= 16;
Edouard@227
   548
                if (*str >= 'a' && *str <= 'f')
Edouard@227
   549
                    *byte += 10 + *str - 'a';
Edouard@227
   550
                else if (*str >= 'A' && *str <= 'F')
Edouard@227
   551
                    *byte += 10 + *str - 'A';
Edouard@227
   552
                else if (*str >= '0' && *str <= '9')
Edouard@227
   553
                    *byte += *str - '0';
Edouard@227
   554
                else 
Edouard@227
   555
                    return 0;
Edouard@227
   556
                str++;
Edouard@227
   557
            }
Edouard@227
   558
            *length++;
Edouard@227
   559
        }
Edouard@227
   560
    }
Edouard@227
   561
    return 1;
Edouard@227
   562
}
Edouard@227
   563
Edouard@174
   564
PEP_STATUS pgp_generate_keypair(
Edouard@174
   565
    PEP_SESSION session, pEp_identity *identity
Edouard@174
   566
    )
Edouard@174
   567
{
Edouard@225
   568
    netpgp_t *netpgp;
Edouard@225
   569
	pgp_key_t	newkey;
Edouard@225
   570
	pgp_key_t	pubkey;
Edouard@225
   571
Edouard@225
   572
    PEP_STATUS result;
Edouard@225
   573
	char newid[1024];
Edouard@225
   574
    const char *hashalg;
Edouard@225
   575
    const char *cipher;
Edouard@174
   576
Edouard@174
   577
    assert(session);
Edouard@174
   578
    assert(identity);
Edouard@174
   579
    assert(identity->address);
Edouard@174
   580
    assert(identity->fpr == NULL);
Edouard@174
   581
    assert(identity->username);
Edouard@174
   582
Edouard@225
   583
    if(!session || !identity || 
Edouard@225
   584
       !identity->address || identity->fpr || !identity->username)
Edouard@225
   585
        return PEP_UNKNOWN_ERROR;
Edouard@174
   586
Edouard@225
   587
    netpgp = &session->ctx;
Edouard@225
   588
Edouard@225
   589
    if(snprintf(newid, sizeof(newid),
Edouard@225
   590
        "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
Edouard@174
   591
        return PEP_BUFFER_TOO_SMALL;
Edouard@174
   592
    }
Edouard@225
   593
    
Edouard@225
   594
    hashalg = netpgp_getvar(netpgp, "hash");
Edouard@225
   595
    cipher = netpgp_getvar(netpgp, "cipher");
Edouard@174
   596
Edouard@225
   597
    bzero(&newkey, sizeof(newkey));
Edouard@225
   598
    bzero(&pubkey, sizeof(pubkey));
Edouard@174
   599
Edouard@225
   600
    // Generate the key
Edouard@225
   601
    if (!pgp_rsa_generate_keypair(&newkey, 4096, 65537UL, hashalg, cipher,
Edouard@225
   602
                                  (const uint8_t *) "", (const size_t) 0) ||
Edouard@227
   603
        !pgp_add_selfsigned_userid(&newkey, (const uint8_t *)newid)) {
Edouard@225
   604
        return PEP_CANNOT_CREATE_KEY;
Edouard@225
   605
	}
Edouard@225
   606
Edouard@225
   607
    // TODO "Expire-Date: 1y\n";
Edouard@225
   608
Edouard@225
   609
    // Duplicate key as public only
Edouard@225
   610
    pgp_keydata_dup(&pubkey, &newkey, 1 /* make_public */);
Edouard@174
   611
Edouard@225
   612
    // Append generated key to netpgp's rings
Edouard@225
   613
    pgp_keyring_add(netpgp->secring, &newkey);
Edouard@225
   614
    pgp_keyring_add(netpgp->pubring, &pubkey);
Edouard@225
   615
    // FIXME doesn't check result since always true 
Edouard@225
   616
    // TODO alloc error feedback in netpgp
Edouard@225
   617
Edouard@227
   618
    // save rings (key ownership transfered)
Edouard@225
   619
    if (netpgp_save_pubring(netpgp) && 
Edouard@225
   620
        netpgp_save_secring(netpgp))
Edouard@225
   621
    {
Edouard@227
   622
        char *fprstr = NULL;
Edouard@227
   623
        fpr_to_str(&fprstr,
Edouard@227
   624
                   newkey.sigfingerprint.fingerprint,
Edouard@227
   625
                   newkey.sigfingerprint.length);
Edouard@227
   626
        if ((identity->fpr = fprstr) == NULL) {
Edouard@225
   627
            result = PEP_OUT_OF_MEMORY;
Edouard@225
   628
        }else{
Edouard@225
   629
            result = PEP_STATUS_OK;
Edouard@225
   630
        }
Edouard@225
   631
    }else{
Edouard@225
   632
        result = PEP_UNKNOWN_ERROR;
Edouard@225
   633
    }
Edouard@174
   634
Edouard@225
   635
    return result;
Edouard@174
   636
}
Edouard@174
   637
Edouard@227
   638
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
Edouard@174
   639
{
Edouard@227
   640
    netpgp_t *netpgp;
Edouard@227
   641
    uint8_t fpr[PGP_FINGERPRINT_SIZE];
Edouard@227
   642
    size_t length;
Edouard@227
   643
    unsigned res;
Edouard@227
   644
Edouard@227
   645
    PEP_STATUS result;
Edouard@227
   646
Edouard@174
   647
    assert(session);
Edouard@174
   648
    assert(fpr);
Edouard@174
   649
Edouard@227
   650
    if (!session || !fpr)
Edouard@174
   651
        return PEP_UNKNOWN_ERROR;
Edouard@174
   652
Edouard@227
   653
    netpgp = &session->ctx;
Edouard@227
   654
    
Edouard@227
   655
    if (str_to_fpr(fprstr, fpr, &length)) {
Edouard@227
   656
        if (!pgp_deletekeybyfpr(netpgp->io,
Edouard@227
   657
                                (pgp_pubkey_t *)netpgp->secring, 
Edouard@227
   658
                                fpr, length)) {
Edouard@227
   659
            return PEP_KEY_NOT_FOUND;
Edouard@227
   660
        }
Edouard@227
   661
    }else{
Edouard@227
   662
        return PEP_OUT_OF_MEMORY;
Edouard@227
   663
    }
Edouard@174
   664
Edouard@227
   665
    /* pair was found in secring delete also corresponding pubkey 
Edouard@227
   666
     * in pubring if it exists */
Edouard@227
   667
    if(res) {
Edouard@227
   668
        pgp_deletekeybyfpr(netpgp->io,
Edouard@227
   669
                           (pgp_pubkey_t *)netpgp->pubring, 
Edouard@227
   670
                           fpr, length);
Edouard@227
   671
    }
Edouard@227
   672
Edouard@227
   673
    // save rings (key ownership transfered)
Edouard@227
   674
    if (netpgp_save_pubring(netpgp) && 
Edouard@227
   675
        netpgp_save_secring(netpgp))
Edouard@227
   676
    {
Edouard@227
   677
        result = PEP_STATUS_OK;
Edouard@227
   678
    }else{
Edouard@227
   679
        result = PEP_UNKNOWN_ERROR;
Edouard@227
   680
    }
Edouard@227
   681
Edouard@227
   682
    return result;
Edouard@174
   683
}
Edouard@174
   684
Edouard@179
   685
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data, size_t size)
Edouard@174
   686
{
Edouard@174
   687
    assert(session);
Edouard@174
   688
    assert(key_data);
Edouard@174
   689
Edouard@174
   690
    /* TODO import */
Edouard@174
   691
        return PEP_UNKNOWN_ERROR;
Edouard@174
   692
        return PEP_ILLEGAL_VALUE;
Edouard@174
   693
        return PEP_UNKNOWN_ERROR;
Edouard@174
   694
    return PEP_STATUS_OK;
Edouard@174
   695
}
Edouard@174
   696
Edouard@179
   697
PEP_STATUS pgp_export_keydata(
Edouard@174
   698
    PEP_SESSION session, const char *fpr, char **key_data, size_t *size
Edouard@174
   699
    )
Edouard@174
   700
{
Edouard@174
   701
    size_t _size;
Edouard@174
   702
    char *buffer;
Edouard@174
   703
    int reading;
Edouard@174
   704
Edouard@174
   705
    assert(session);
Edouard@174
   706
    assert(fpr);
Edouard@174
   707
    assert(key_data);
Edouard@174
   708
    assert(size);
Edouard@174
   709
Edouard@174
   710
Edouard@174
   711
    /* TODO export */
Edouard@174
   712
        return PEP_KEY_NOT_FOUND;
Edouard@174
   713
        return PEP_UNKNOWN_ERROR;
Edouard@174
   714
        return PEP_UNKNOWN_ERROR;
Edouard@174
   715
Edouard@174
   716
    _size = /* TODO */ 0;
Edouard@174
   717
    assert(_size != -1);
Edouard@174
   718
Edouard@174
   719
    buffer = malloc(_size + 1);
Edouard@174
   720
    assert(buffer);
Edouard@174
   721
    if (buffer == NULL) {
Edouard@174
   722
        /* TODO clean */
Edouard@174
   723
        return PEP_OUT_OF_MEMORY;
Edouard@174
   724
    }
Edouard@174
   725
Edouard@174
   726
    // safeguard for the naive user
Edouard@174
   727
    buffer[_size] = 0;
Edouard@174
   728
Edouard@174
   729
    *key_data = buffer;
Edouard@174
   730
    *size = _size;
Edouard@174
   731
Edouard@174
   732
    return PEP_STATUS_OK;
Edouard@174
   733
}
Edouard@174
   734
Edouard@175
   735
// "keyserver"
Edouard@175
   736
// "hkp://keys.gnupg.net"
Edouard@174
   737
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
Edouard@174
   738
{
Edouard@174
   739
    assert(session);
Edouard@174
   740
    assert(pattern);
Edouard@174
   741
Edouard@174
   742
    /* TODO ask for key */
Edouard@174
   743
        return PEP_UNKNOWN_ERROR;
Edouard@174
   744
        return PEP_GET_KEY_FAILED;
Edouard@174
   745
Edouard@174
   746
    do {
Edouard@174
   747
Edouard@174
   748
        /* For each key */
Edouard@174
   749
        /* import key */
Edouard@174
   750
    } while (0);
Edouard@174
   751
Edouard@174
   752
    return PEP_STATUS_OK;
Edouard@174
   753
}
Edouard@174
   754
Edouard@174
   755
PEP_STATUS pgp_find_keys(
Edouard@174
   756
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
Edouard@174
   757
    )
Edouard@174
   758
{
Edouard@174
   759
    stringlist_t *_keylist;
Edouard@174
   760
    char *fpr;
Edouard@174
   761
Edouard@174
   762
    assert(session);
Edouard@174
   763
    assert(pattern);
Edouard@174
   764
    assert(keylist);
Edouard@174
   765
Edouard@174
   766
    *keylist = NULL;
Edouard@174
   767
Edouard@174
   768
    /* Ask for key */
Edouard@174
   769
        return PEP_UNKNOWN_ERROR;
Edouard@174
   770
        return PEP_GET_KEY_FAILED;
Edouard@174
   771
Edouard@174
   772
    _keylist = new_stringlist(NULL);
Edouard@174
   773
    stringlist_t *_k = _keylist;
Edouard@174
   774
Edouard@174
   775
    do {
Edouard@174
   776
            fpr = "TODO key->subkeys->fpr";
Edouard@174
   777
            assert(fpr);
Edouard@174
   778
            _k = stringlist_add(_k, fpr);
Edouard@174
   779
            assert(_k);
Edouard@174
   780
            if (_k == NULL){
Edouard@174
   781
                free_stringlist(_keylist);
Edouard@174
   782
                return PEP_OUT_OF_MEMORY;
Edouard@174
   783
            }
Edouard@174
   784
    } while (0);
Edouard@174
   785
Edouard@174
   786
    *keylist = _keylist;
Edouard@174
   787
    return PEP_STATUS_OK;
Edouard@174
   788
}
Edouard@174
   789
Edouard@174
   790
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
Edouard@174
   791
{
Edouard@174
   792
    assert(session);
Edouard@174
   793
    assert(pattern);
Edouard@174
   794
Edouard@174
   795
    /* TODO send key */
Edouard@174
   796
Edouard@174
   797
        return PEP_CANNOT_SEND_KEY;
Edouard@174
   798
        return PEP_STATUS_OK;
Edouard@174
   799
}
Edouard@174
   800
Edouard@174
   801
Edouard@174
   802
PEP_STATUS pgp_get_key_rating(
Edouard@174
   803
    PEP_SESSION session,
Edouard@174
   804
    const char *fpr,
Edouard@174
   805
    PEP_comm_type *comm_type
Edouard@174
   806
    )
Edouard@174
   807
{
Edouard@174
   808
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@174
   809
Edouard@174
   810
    assert(session);
Edouard@174
   811
    assert(fpr);
Edouard@174
   812
    assert(comm_type);
Edouard@174
   813
Edouard@174
   814
    *comm_type = PEP_ct_unknown;
Edouard@174
   815
Edouard@174
   816
    /* TODO get key from fpr */
Edouard@174
   817
    return PEP_UNKNOWN_ERROR;
Edouard@174
   818
    return PEP_GET_KEY_FAILED;
Edouard@174
   819
Edouard@174
   820
    switch (/*TODO key->protocol*/ 4) {
Edouard@174
   821
    case /* TODO  OpenPGP */0:
Edouard@174
   822
    case /* TODO DEFAULT */1:
Edouard@174
   823
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
Edouard@174
   824
        break;
Edouard@174
   825
    case /* TODO CMS */2:
Edouard@174
   826
        *comm_type = PEP_ct_CMS_unconfirmed;
Edouard@174
   827
        break;
Edouard@174
   828
    default:
Edouard@174
   829
        *comm_type = PEP_ct_unknown;
Edouard@174
   830
        return PEP_STATUS_OK;
Edouard@174
   831
    }
Edouard@174
   832
Edouard@174
   833
        for (; 1 == 0; /* Each subkeys */ ) {
Edouard@174
   834
            if (/* TODO length */0 < 1024)
Edouard@174
   835
                *comm_type = PEP_ct_key_too_short;
Edouard@174
   836
            else if (
Edouard@174
   837
                (
Edouard@174
   838
                (   /* TODO pubkey_algo == RSA  */ 0)
Edouard@174
   839
                || (/* TODO pubkey_algo == RSA_E*/ 0)
Edouard@174
   840
                || (/* TODO pubkey_algo == RSA_S*/ 0)
Edouard@174
   841
                )
Edouard@174
   842
                && /* sk->length */0 == 1024
Edouard@174
   843
                )
Edouard@174
   844
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
Edouard@174
   845
Edouard@174
   846
            if (/* TODO invalid */ 1) {
Edouard@174
   847
                *comm_type = PEP_ct_key_b0rken;
Edouard@174
   848
                break;
Edouard@174
   849
            }
Edouard@174
   850
            if (/* TODO expired */ 1) {
Edouard@174
   851
                *comm_type = PEP_ct_key_expired;
Edouard@174
   852
                break;
Edouard@174
   853
            }
Edouard@175
   854
            if (/* TODO revoked*/ 1) {
Edouard@174
   855
                *comm_type = PEP_ct_key_revoked;
Edouard@174
   856
                break;
Edouard@174
   857
            }
Edouard@174
   858
        }
Edouard@174
   859
        *comm_type = PEP_ct_unknown;
Edouard@174
   860
        return PEP_OUT_OF_MEMORY;
Edouard@174
   861
        return PEP_UNKNOWN_ERROR;
Edouard@174
   862
Edouard@174
   863
Edouard@174
   864
    return status;
Edouard@174
   865
}
Edouard@210
   866
Edouard@210
   867
PEP_STATUS pgp_renew_key(
Edouard@210
   868
        PEP_SESSION session,
Edouard@210
   869
        const char *fpr,
Edouard@210
   870
        const timestamp *ts
Edouard@210
   871
    )
Edouard@210
   872
{
Edouard@210
   873
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
   874
    char date_text[12];
Edouard@210
   875
Edouard@210
   876
    assert(session);
Edouard@210
   877
    assert(fpr);
Edouard@210
   878
Edouard@210
   879
    snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
Edouard@210
   880
            ts->tm_mon + 1, ts->tm_mday);
Edouard@210
   881
Edouard@210
   882
Edouard@210
   883
        return PEP_UNKNOWN_ERROR;
Edouard@210
   884
    return PEP_STATUS_OK;
Edouard@210
   885
}
Edouard@210
   886
Edouard@226
   887
PEP_STATUS pgp_revoke_key(
Edouard@226
   888
        PEP_SESSION session,
Edouard@226
   889
        const char *fpr,
Edouard@226
   890
        const char *reason
Edouard@226
   891
    )
Edouard@210
   892
{
Edouard@210
   893
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@210
   894
    
Edouard@210
   895
    assert(session);
Edouard@210
   896
    assert(fpr);
Edouard@210
   897
Edouard@210
   898
        return PEP_UNKNOWN_ERROR;
Edouard@210
   899
Edouard@210
   900
    return PEP_STATUS_OK;
Edouard@210
   901
}
Edouard@210
   902
Edouard@226
   903
PEP_STATUS pgp_key_expired(
Edouard@226
   904
        PEP_SESSION session,
Edouard@226
   905
        const char *fpr,
Edouard@226
   906
        bool *expired
Edouard@226
   907
    )
Edouard@226
   908
{
Edouard@226
   909
    PEP_STATUS status = PEP_STATUS_OK;
Edouard@226
   910
Edouard@226
   911
    assert(session);
Edouard@226
   912
    assert(fpr);
Edouard@226
   913
    assert(expired);
Edouard@226
   914
Edouard@226
   915
    *expired = false;
Edouard@226
   916
Edouard@226
   917
    if (status != PEP_STATUS_OK)
Edouard@226
   918
        return status;
Edouard@226
   919
Edouard@226
   920
    return PEP_STATUS_OK;
Edouard@226
   921
}
Edouard@226
   922