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