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