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