src/pgp_netpgp.c
author Roker <roker@pep-project.org>
Thu, 26 Jan 2017 19:07:45 +0100
changeset 1559 c6506bc6a0df
parent 1513 e7f7e42385b5
child 1673 559931685411
child 1674 5639f969866a
permissions -rw-r--r--
avoid unitialized local pointer variables to reduce hard-to-find bugs
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "pEp_internal.h"
     5 #include "pgp_netpgp.h"
     6 
     7 #include <limits.h>
     8 
     9 #include "wrappers.h"
    10 
    11 #include "netpgp.h"
    12 #include <netpgp/config.h>
    13 #include <netpgp/memory.h>
    14 #include <netpgp/crypto.h>
    15 #include <netpgp/netpgpsdk.h>
    16 #include <netpgp/validate.h>
    17 #include <netpgp/readerwriter.h>
    18 
    19 #include <curl/curl.h>
    20 #include <pthread.h>
    21 #include <regex.h>
    22 
    23 static netpgp_t netpgp;
    24 static pthread_mutex_t netpgp_mutex;
    25 
    26 static PEP_STATUS init_netpgp()
    27 {
    28     PEP_STATUS status = PEP_STATUS_OK;
    29     const char *home = NULL;
    30 
    31     if(pthread_mutex_init(&netpgp_mutex, NULL)){
    32         return PEP_OUT_OF_MEMORY;
    33     }
    34 
    35     if(pthread_mutex_lock(&netpgp_mutex)){
    36         return PEP_UNKNOWN_ERROR;
    37     }
    38 
    39     if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
    40         setlocale(LC_ALL, "");
    41 
    42     memset(&netpgp, 0x0, sizeof(netpgp_t));
    43 
    44     // netpgp_setvar(&netpgp, "max mem alloc", "4194304");
    45     netpgp_setvar(&netpgp, "need seckey", "1");
    46     // netpgp_setvar(&netpgp, "need userid", "1");
    47 
    48     // NetPGP shares home with GPG
    49     home = gpg_home();
    50     if(home){
    51         netpgp_set_homedir(&netpgp,(char*)home, NULL, 0);
    52     }else{
    53         status = PEP_INIT_NO_GPG_HOME;
    54         goto unlock_netpgp;
    55     }
    56 
    57     // pair with gpg's cert-digest-algo
    58     netpgp_setvar(&netpgp, "hash", "SHA256");
    59 
    60     // subset of gpg's personal-cipher-preferences
    61     // here only one cipher can be selected
    62     netpgp_setvar(&netpgp, "cipher", "CAST5");
    63 
    64     if (!netpgp_init(&netpgp)) {
    65         status = PEP_INIT_NETPGP_INIT_FAILED;
    66         goto unlock_netpgp;
    67     }
    68 
    69     // netpgp_set_debug("packet-parse.c");
    70 
    71 unlock_netpgp:
    72     pthread_mutex_unlock(&netpgp_mutex);
    73 
    74     return status;
    75 }
    76 
    77 static void release_netpgp()
    78 {
    79     if(pthread_mutex_lock(&netpgp_mutex)){
    80         return;
    81     }
    82     netpgp_end(&netpgp);
    83     memset(&netpgp, 0x0, sizeof(netpgp_t));
    84 
    85     pthread_mutex_destroy(&netpgp_mutex);
    86 
    87     return;
    88 }
    89 
    90 static PEP_STATUS init_curl(
    91     pthread_mutex_t *curl_mutex,
    92     bool in_first)
    93 {
    94     PEP_STATUS status = PEP_STATUS_OK;
    95 
    96     if(pthread_mutex_init(curl_mutex, NULL)){
    97         return PEP_OUT_OF_MEMORY;
    98     }
    99 
   100     if(pthread_mutex_lock(curl_mutex)){
   101         return PEP_UNKNOWN_ERROR;
   102     }
   103 
   104     if(in_first){
   105         curl_global_init(CURL_GLOBAL_DEFAULT);
   106     }
   107 
   108     pthread_mutex_unlock(curl_mutex);
   109     return status;
   110 }
   111 
   112 static void release_curl(
   113     pthread_mutex_t *curl_mutex,
   114     bool out_last)
   115 {
   116     if(pthread_mutex_lock(curl_mutex)){
   117         return;
   118     }
   119 
   120     if(out_last){
   121         curl_global_cleanup();
   122     }
   123 
   124     pthread_mutex_destroy(curl_mutex);
   125 
   126     return;
   127 }
   128 
   129 static PEP_STATUS curl_get_ctx(
   130     CURL **curl)
   131 {
   132     PEP_STATUS status = PEP_STATUS_OK;
   133     struct curl_slist *headers=NULL;
   134 
   135     if ((*curl = curl_easy_init()) == NULL) {
   136         return PEP_OUT_OF_MEMORY;
   137     }
   138 
   139     curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
   140     curl_easy_setopt(*curl, CURLOPT_MAXREDIRS, 3L);
   141 
   142     headers=curl_slist_append(headers,"Pragma: no-cache");
   143     if(headers)
   144         headers=curl_slist_append(headers,"Cache-Control: no-cache");
   145 
   146     if(!headers)
   147     {
   148         return PEP_OUT_OF_MEMORY;
   149     }
   150 
   151     curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
   152     curl_slist_free_all(headers);
   153 
   154     // TODO curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
   155     return status;
   156 }
   157 
   158 static void curl_release_ctx(
   159     CURL **curl)
   160 {
   161     if(*curl)
   162         curl_easy_cleanup(*curl);
   163 
   164     *curl = NULL;
   165 
   166     return;
   167 }
   168 
   169 PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   170 {
   171     PEP_STATUS status = PEP_STATUS_OK;
   172 
   173     assert(session);
   174     if(!session) return PEP_ILLEGAL_VALUE;
   175 
   176     if (in_first) {
   177         if((status = init_netpgp()) != PEP_STATUS_OK)
   178         return status;
   179     }
   180 
   181     if((status = init_curl(
   182                     &session->ctx.curl_mutex,
   183                     in_first) != PEP_STATUS_OK)){
   184         if(in_first) release_netpgp();
   185         return status;
   186     }
   187 
   188     return PEP_STATUS_OK;
   189 }
   190 
   191 void pgp_release(PEP_SESSION session, bool out_last)
   192 {
   193     assert(session);
   194     if(!session) return;
   195 
   196     if (out_last){
   197         release_netpgp();
   198     }
   199     release_curl(&session->ctx.curl_mutex, out_last);
   200 }
   201 
   202 // return 1 if the file contains ascii-armoured text
   203 static unsigned
   204 _armoured(const char *buf, size_t size, const char *pattern)
   205 {
   206     unsigned armoured = 0;
   207     regex_t r;
   208     regcomp(&r, pattern, REG_EXTENDED|REG_NOSUB);
   209     if (regnexec(&r, buf, size, 0, NULL, 0) == 0) {
   210         armoured = 1;
   211     }
   212     regfree(&r);
   213     return armoured;
   214 }
   215 
   216 /* write key fingerprint hexdump as a string */
   217 static unsigned
   218 fpr_to_str (char **str, const uint8_t *fpr, size_t length)
   219 {
   220     unsigned i;
   221     int	n;
   222 
   223     /* 4 hexes per short + null */
   224     *str = malloc((length / 2) * 4 + 1);
   225 
   226     if(*str == NULL)
   227         return 0;
   228 
   229     for (n = 0, i = 0 ; i < length; i += 2) {
   230         n += snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
   231     }
   232 
   233     return 1;
   234 }
   235 
   236 /* write key fingerprint bytes read from hex string
   237  * accept spaces and hexes */
   238 static unsigned
   239 str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
   240 {
   241     unsigned i,j;
   242 
   243     *length = 0;
   244 
   245     while(*str && *length < PGP_FINGERPRINT_SIZE){
   246         while (*str == ' ') str++;
   247         for (j = 0; j < 2; j++) {
   248             uint8_t *byte = &fpr[*length];
   249             *byte = 0;
   250             for (i = 0; i < 2; i++) {
   251                 if (i > 0)
   252                     *byte = *byte << 4;
   253                 if (*str >= 'a' && *str <= 'f')
   254                     *byte += 10 + *str - 'a';
   255                 else if (*str >= 'A' && *str <= 'F')
   256                     *byte += 10 + *str - 'A';
   257                 else if (*str >= '0' && *str <= '9')
   258                     *byte += *str - '0';
   259                 else
   260                     return 0;
   261                 str++;
   262             }
   263             (*length)++;
   264         }
   265     }
   266     return 1;
   267 }
   268 
   269 // Iterate through netpgp' reported valid signatures
   270 // fill a list of valid figerprints
   271 // returns PEP_STATUS_OK if all sig reported valid
   272 // error status otherwise.
   273 static PEP_STATUS _validation_results(
   274         netpgp_t *netpgp,
   275         pgp_validation_t *vresult,
   276         stringlist_t **_keylist
   277     )
   278 {
   279     time_t    now;
   280     time_t    t;
   281 
   282     now = time(NULL);
   283     if (now < vresult->birthtime) {
   284         // signature is not valid yet
   285         return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   286     }
   287     if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
   288         // signature has expired
   289         t = vresult->duration + vresult->birthtime;
   290         return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   291     }
   292     if (vresult->validc && vresult->valid_sigs &&
   293         !vresult->invalidc && !vresult->unknownc ) {
   294         
   295         // caller responsible to free
   296         *_keylist = new_stringlist(NULL);
   297         assert(*_keylist);
   298         if (*_keylist == NULL) {
   299             return PEP_OUT_OF_MEMORY;
   300         }
   301         
   302         stringlist_t *k = *_keylist;
   303         for (unsigned n = 0; n < vresult->validc; ++n) {
   304             unsigned from = 0;
   305             const pgp_key_t	 *signer;
   306             char *fprstr = NULL;
   307             const uint8_t *keyid = vresult->valid_sigs[n].signer_id;
   308 
   309             signer = pgp_getkeybyid(netpgp->io, netpgp->pubring,
   310                                     keyid, &from, NULL, NULL,
   311                                     0, 0); /* check neither revocation nor expiry
   312                                               as is should be checked already */
   313             if(signer)
   314                 fpr_to_str(&fprstr,
   315                            signer->pubkeyfpr.fingerprint,
   316                            signer->pubkeyfpr.length);
   317             else
   318                 return PEP_VERIFY_NO_KEY;
   319 
   320             if (fprstr == NULL)
   321                 return PEP_OUT_OF_MEMORY;
   322 
   323             k = stringlist_add(k, fprstr);
   324 
   325             free(fprstr);
   326 
   327             if(!k){
   328                 free_stringlist(*_keylist);
   329                 return PEP_OUT_OF_MEMORY;
   330             }
   331         }
   332         return PEP_STATUS_OK;
   333     }
   334     if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
   335         // No signatures found - is this memory signed?
   336         return PEP_VERIFY_NO_KEY;
   337     }
   338 
   339     if (vresult->invalidc) {
   340         // some invalid signatures
   341         return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   342     }
   343 
   344     // only unknown sigs
   345     return PEP_DECRYPTED;
   346 }
   347 
   348 #define _ENDL    "\\s*(\r\n|\r|\n)"
   349 #define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----"_ENDL
   350 PEP_STATUS pgp_decrypt_and_verify(
   351     PEP_SESSION session, const char *ctext, size_t csize,
   352     const char *dsigtext, size_t dsigsize,
   353     char **ptext, size_t *psize, stringlist_t **keylist
   354     )
   355 {
   356     char *_ptext = NULL;
   357 
   358     PEP_STATUS result;
   359     stringlist_t *_keylist = NULL;
   360 
   361     assert(session);
   362     assert(ctext);
   363     assert(csize);
   364     assert(ptext);
   365     assert(psize);
   366     assert(keylist);
   367 
   368     if(!session || !ctext || !csize || !ptext || !psize || !keylist)
   369         return PEP_ILLEGAL_VALUE;
   370 
   371     if(pthread_mutex_lock(&netpgp_mutex)){
   372         return PEP_UNKNOWN_ERROR;
   373     }
   374 
   375     *ptext = NULL;
   376     *psize = 0;
   377     *keylist = NULL;
   378 
   379     pgp_validation_t *vresult = malloc(sizeof(pgp_validation_t));
   380     memset(vresult, 0x0, sizeof(pgp_validation_t));
   381 
   382     pgp_memory_t *mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
   383                 netpgp.secring, netpgp.pubring,
   384                 _armoured(ctext, csize, ARMOR_HEAD),
   385                 0 /* sshkeys */,
   386                 NULL, -1, NULL  /* pass fp,attempts,cb */);
   387     if (mem == NULL) {
   388         result = PEP_OUT_OF_MEMORY;
   389         goto unlock_netpgp;
   390     }
   391 
   392     const size_t _psize = pgp_mem_len(mem);
   393     if (_psize){
   394         if ((_ptext = malloc(_psize + 1)) == NULL) {
   395             result = PEP_OUT_OF_MEMORY;
   396             goto free_pgp;
   397         }
   398         memcpy(_ptext, pgp_mem_data(mem), _psize);
   399         _ptext[_psize] = '\0'; // safeguard for naive users
   400         result = PEP_DECRYPTED;
   401     }else{
   402         result = PEP_DECRYPT_NO_KEY;
   403         goto free_pgp;
   404     }
   405 
   406     if (result == PEP_DECRYPTED) {
   407         result = _validation_results(&netpgp, vresult, &_keylist);
   408         if (result == PEP_DECRYPTED) {
   409             //no change
   410         } else if (result == PEP_VERIFY_NO_KEY) {
   411             result = PEP_DECRYPTED;
   412         }else if (result != PEP_STATUS_OK) {
   413             goto free_ptext;
   414         }else{
   415             result = PEP_DECRYPTED_AND_VERIFIED;
   416         }
   417     }
   418 
   419     if (result == PEP_DECRYPTED_AND_VERIFIED
   420         || result == PEP_DECRYPTED) {
   421         *ptext = _ptext;
   422         *psize = _psize;
   423         (*ptext)[*psize] = 0; // safeguard for naive users
   424         if (result == PEP_DECRYPTED_AND_VERIFIED) {
   425             *keylist = _keylist;
   426         }
   427 
   428         /* _ptext and _keylist ownership transfer, don't free */
   429         goto free_pgp;
   430     }
   431 
   432 free_keylist:
   433     free_stringlist(_keylist);
   434 
   435 free_ptext:
   436     free(_ptext);
   437 
   438 free_pgp:
   439     pgp_memory_free(mem);
   440     pgp_validate_result_free(vresult);
   441 
   442 unlock_netpgp:
   443     pthread_mutex_unlock(&netpgp_mutex);
   444 
   445     return result;
   446 }
   447 
   448 #define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"_ENDL
   449 PEP_STATUS pgp_verify_text(
   450     PEP_SESSION session, const char *text, size_t size,
   451     const char *signature, size_t sig_size, stringlist_t **keylist
   452     )
   453 {
   454     pgp_memory_t *signedmem;
   455     pgp_memory_t *sig;
   456     pgp_validation_t *vresult;
   457 
   458     PEP_STATUS result;
   459     stringlist_t *_keylist;
   460 
   461     assert(session);
   462     assert(text);
   463     assert(size);
   464     assert(signature);
   465     assert(sig_size);
   466     assert(keylist);
   467 
   468     if(!session || !text || !size || !signature || !sig_size || !keylist)
   469         return PEP_ILLEGAL_VALUE;
   470 
   471     if(pthread_mutex_lock(&netpgp_mutex)){
   472         return PEP_UNKNOWN_ERROR;
   473     }
   474 
   475     *keylist = NULL;
   476 
   477     vresult = malloc(sizeof(pgp_validation_t));
   478     if (vresult == NULL) {
   479         result = PEP_OUT_OF_MEMORY;
   480         goto unlock_netpgp;
   481     }
   482     memset(vresult, 0x0, sizeof(pgp_validation_t));
   483 
   484     signedmem = pgp_memory_new();
   485     if (signedmem == NULL) {
   486         result = PEP_OUT_OF_MEMORY;
   487         goto unlock_netpgp;
   488     }
   489     pgp_memory_add(signedmem, (const uint8_t*)text, size);
   490 
   491     sig = pgp_memory_new();
   492     if (sig == NULL) {
   493         pgp_memory_free(signedmem);
   494         result = PEP_OUT_OF_MEMORY;
   495         goto unlock_netpgp;
   496     }
   497     pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
   498 
   499     pgp_validate_mem_detached(netpgp.io, vresult, sig,
   500                 NULL,/* output */
   501                 _armoured(signature, sig_size, ARMOR_SIG_HEAD),
   502                 netpgp.pubring,
   503                 signedmem);
   504 
   505     result = _validation_results(&netpgp, vresult, &_keylist);
   506     if (result != PEP_STATUS_OK) {
   507         goto free_pgp;
   508     }else{
   509         result = PEP_VERIFIED;
   510     }
   511 
   512     if (result == PEP_VERIFIED) {
   513         /* TODO : check trust level */
   514         result = PEP_VERIFIED_AND_TRUSTED;
   515     }
   516 
   517     if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
   518         *keylist = _keylist;
   519 
   520         /* _keylist ownership transfer, don't free */
   521         goto free_pgp;
   522     }
   523 
   524 free_keylist:
   525     free_stringlist(_keylist);
   526 
   527 free_pgp:
   528     // free done by pgp_validate_mem_detached
   529     // pgp_memory_free(sig);
   530     // pgp_memory_free(signedmem);
   531     pgp_validate_result_free(vresult);
   532 
   533 unlock_netpgp:
   534     pthread_mutex_unlock(&netpgp_mutex);
   535 
   536     return result;
   537 }
   538 
   539 PEP_STATUS pgp_encrypt_and_sign(
   540     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   541     size_t psize, char **ctext, size_t *csize
   542     )
   543 {
   544     pgp_key_t *signer = NULL;
   545     pgp_seckey_t *seckey = NULL;
   546     pgp_memory_t *signedmem;
   547     pgp_memory_t *cmem;
   548     const char *hashalg;
   549     pgp_keyring_t *rcpts;
   550 
   551     PEP_STATUS result;
   552     const stringlist_t *_keylist;
   553 
   554     assert(session);
   555     assert(keylist);
   556     assert(ptext);
   557     assert(psize);
   558     assert(ctext);
   559     assert(csize);
   560 
   561     if(!session || !ptext || !psize || !ctext || !csize || !keylist)
   562         return PEP_ILLEGAL_VALUE;
   563 
   564     if(pthread_mutex_lock(&netpgp_mutex)){
   565         return PEP_UNKNOWN_ERROR;
   566     }
   567 
   568     *ctext = NULL;
   569     *csize = 0;
   570 
   571     if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
   572         result = PEP_OUT_OF_MEMORY;
   573         goto unlock_netpgp;
   574     }
   575     for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
   576         assert(_keylist->value);
   577 
   578         const pgp_key_t *key;
   579         uint8_t fpr[PGP_FINGERPRINT_SIZE];
   580         size_t fprlen;
   581         unsigned from = 0;
   582 
   583         if (str_to_fpr(_keylist->value, fpr, &fprlen)) {
   584             if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
   585                                                     fpr, fprlen, &from, NULL,
   586                                                     /* reject revoked, accept expired */
   587                                                     1,0)) == NULL) {
   588                 result = PEP_KEY_NOT_FOUND;
   589                 goto free_rcpts;
   590             }
   591         }else{
   592             result = PEP_ILLEGAL_VALUE;
   593             goto free_rcpts;
   594         }
   595 
   596         /* Signer is the first key in the list */
   597         if(signer == NULL){
   598             from = 0;
   599             signer = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.secring,
   600                                                   fpr, fprlen,
   601                                                   &from,
   602                                                   NULL,
   603                                                   0,0); /* accept any */
   604             if(signer == NULL){
   605                 result = PEP_KEY_NOT_FOUND;
   606                 goto free_rcpts;
   607             }
   608         }
   609 
   610         // add key to recipients/signers
   611         pgp_keyring_add(rcpts, key);
   612         if(rcpts->keys == NULL){
   613             result = PEP_OUT_OF_MEMORY;
   614             goto free_rcpts;
   615         }
   616     }
   617 
   618     /* Empty keylist ?*/
   619     if(rcpts->keyc == 0){
   620         result = PEP_ILLEGAL_VALUE;
   621         goto free_rcpts;
   622     }
   623 
   624     seckey = pgp_key_get_certkey(signer);
   625 
   626     /* No signig key. Revoked ? */
   627     if(seckey == NULL){
   628         result = PEP_GET_KEY_FAILED;
   629         goto free_rcpts;
   630     }
   631 
   632     hashalg = netpgp_getvar(&netpgp, "hash");
   633 
   634     // Sign data
   635     signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
   636                 time(NULL), /* birthtime */
   637                 0 /* duration */,
   638                 hashalg,
   639                 0 /* armored */,
   640                 0 /* cleartext */);
   641 
   642     if (!signedmem) {
   643         result = PEP_UNENCRYPTED;
   644         goto free_rcpts;
   645     }
   646 
   647     // Encrypt signed data
   648 
   649     cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
   650             pgp_mem_len(signedmem), rcpts, 1 /* armored */,
   651             netpgp_getvar(&netpgp, "cipher"),
   652             1 /* takes raw OpenPGP message */);
   653 
   654     if (cmem == NULL) {
   655         result = PEP_OUT_OF_MEMORY;
   656         goto free_signedmem;
   657     }else{
   658 
   659         char *_buffer = NULL;
   660         size_t length = pgp_mem_len(cmem);
   661 
   662         // Allocate transferable buffer
   663         _buffer = malloc(length + 1);
   664         assert(_buffer);
   665         if (_buffer == NULL) {
   666             result = PEP_OUT_OF_MEMORY;
   667             goto free_cmem;
   668         }
   669 
   670         memcpy(_buffer, pgp_mem_data(cmem), length);
   671 
   672         *ctext = _buffer;
   673         *csize = length;
   674         (*ctext)[*csize] = 0; // safeguard for naive users
   675         result = PEP_STATUS_OK;
   676     }
   677 
   678 free_cmem :
   679     pgp_memory_free(cmem);
   680 free_signedmem :
   681     pgp_memory_free(signedmem);
   682 free_rcpts :
   683     pgp_keyring_free(rcpts);
   684 unlock_netpgp:
   685     pthread_mutex_unlock(&netpgp_mutex);
   686 
   687     return result;
   688 }
   689 
   690 PEP_STATUS pgp_generate_keypair(
   691     PEP_SESSION session, pEp_identity *identity
   692     )
   693 {
   694     pgp_key_t	newseckey;
   695     pgp_key_t	*newpubkey;
   696 
   697     PEP_STATUS result;
   698     char newid[1024];
   699     const char *hashalg;
   700     const char *cipher;
   701 
   702     assert(session);
   703     assert(identity);
   704     assert(identity->address);
   705     assert(identity->fpr == NULL);
   706     assert(identity->username);
   707 
   708     if(!session || !identity ||
   709        !identity->address || identity->fpr || !identity->username)
   710         return PEP_ILLEGAL_VALUE;
   711 
   712     if(pthread_mutex_lock(&netpgp_mutex)){
   713         return PEP_UNKNOWN_ERROR;
   714     }
   715 
   716     if(snprintf(newid, sizeof(newid),
   717         "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
   718         result =  PEP_BUFFER_TOO_SMALL;
   719         goto unlock_netpgp;
   720     }
   721 
   722     hashalg = netpgp_getvar(&netpgp, "hash");
   723     cipher = netpgp_getvar(&netpgp, "cipher");
   724 
   725     bzero(&newseckey, sizeof(newseckey));
   726 
   727     // Generate the key
   728     if (!pgp_rsa_generate_keypair(&newseckey, 4096, 65537UL, hashalg, cipher,
   729                                   (const uint8_t *) "", (const size_t) 0))
   730     {
   731         result = PEP_CANNOT_CREATE_KEY;
   732         goto free_seckey;
   733     }
   734 
   735     /* make a public key out of generated secret key */
   736     if((newpubkey = pgp_ensure_pubkey(
   737             netpgp.pubring,
   738             &newseckey.key.seckey.pubkey,
   739             newseckey.pubkeyid))==NULL)
   740     {
   741         result = PEP_OUT_OF_MEMORY;
   742         goto free_seckey;
   743     }
   744 
   745     // "Expire-Date: 1y\n";
   746     if (!pgp_add_selfsigned_userid(&newseckey, newpubkey,
   747                                   (uint8_t *)newid, 365*24*3600))
   748     {
   749         result = PEP_CANNOT_CREATE_KEY;
   750         goto delete_pubkey;
   751     }
   752 
   753     if (newpubkey == NULL)
   754     {
   755         result = PEP_OUT_OF_MEMORY;
   756         goto delete_pubkey;
   757     }
   758 
   759     // Append key to netpgp's rings (key ownership transfered)
   760     if (!pgp_keyring_add(netpgp.secring, &newseckey)){
   761         result = PEP_OUT_OF_MEMORY;
   762         goto delete_pubkey;
   763     }
   764 
   765     // save rings
   766     if (netpgp_save_pubring(&netpgp) && netpgp_save_secring(&netpgp))
   767     {
   768         char *fprstr = NULL;
   769         fpr_to_str(&fprstr,
   770                    newseckey.pubkeyfpr.fingerprint,
   771                    newseckey.pubkeyfpr.length);
   772 
   773         if (fprstr == NULL) {
   774             result = PEP_OUT_OF_MEMORY;
   775             goto pop_secring;
   776         }
   777 
   778         /* keys saved, pass fingerprint back */
   779         identity->fpr = fprstr;
   780         result = PEP_STATUS_OK;
   781 
   782         /* free nothing, everything transfered */
   783         goto unlock_netpgp;
   784     } else {
   785         /* XXX in case only pubring save succeed
   786          * pubring file is left as-is, but backup restore
   787          * could be attempted if such corner case matters */
   788         result = PEP_UNKNOWN_ERROR;
   789     }
   790 
   791 pop_secring:
   792     ((pgp_keyring_t *)netpgp.secring)->keyc--;
   793 delete_pubkey:
   794     pgp_deletekeybyfpr(netpgp.io,
   795                     (pgp_keyring_t *)netpgp.pubring,
   796                     newseckey.pubkeyfpr.fingerprint,
   797                     newseckey.pubkeyfpr.length);
   798 free_seckey:
   799     pgp_key_free(&newseckey);
   800 unlock_netpgp:
   801     pthread_mutex_unlock(&netpgp_mutex);
   802 
   803     return result;
   804 }
   805 
   806 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
   807 {
   808     uint8_t fpr[PGP_FINGERPRINT_SIZE];
   809     size_t length;
   810 
   811     PEP_STATUS result;
   812 
   813     assert(session);
   814     assert(fprstr);
   815 
   816     if (!session || !fprstr)
   817         return PEP_ILLEGAL_VALUE;
   818 
   819     if(pthread_mutex_lock(&netpgp_mutex)){
   820         return PEP_UNKNOWN_ERROR;
   821     }
   822 
   823     if (str_to_fpr(fprstr, fpr, &length)) {
   824         unsigned insec = pgp_deletekeybyfpr(netpgp.io,
   825                                 (pgp_keyring_t *)netpgp.secring,
   826                                 (const uint8_t *)fpr, length);
   827         unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
   828                                 (pgp_keyring_t *)netpgp.pubring,
   829                                 (const uint8_t *)fpr, length);
   830         if(!insec && !inpub){
   831             result = PEP_KEY_NOT_FOUND;
   832             goto unlock_netpgp;
   833         } else {
   834             result = PEP_STATUS_OK;
   835         }
   836     }else{
   837         result = PEP_OUT_OF_MEMORY;
   838         goto unlock_netpgp;
   839     }
   840 
   841     // save rings
   842     if (netpgp_save_pubring(&netpgp) &&
   843         netpgp_save_secring(&netpgp))
   844     {
   845         result = PEP_STATUS_OK;
   846     }else{
   847         result = PEP_UNKNOWN_ERROR;
   848     }
   849 
   850 unlock_netpgp:
   851     pthread_mutex_unlock(&netpgp_mutex);
   852 
   853     return result;
   854 }
   855 
   856 #define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----"_ENDL
   857 PEP_STATUS pgp_import_keydata(
   858         PEP_SESSION session,
   859         const char *key_data,
   860         size_t size
   861     )
   862 {
   863     pgp_memory_t *mem;
   864 
   865     PEP_STATUS result = PEP_STATUS_OK;
   866 
   867     assert(session);
   868     assert(key_data);
   869 
   870     if(!session || !key_data)
   871         return PEP_ILLEGAL_VALUE;
   872 
   873     if(pthread_mutex_lock(&netpgp_mutex)){
   874         return PEP_UNKNOWN_ERROR;
   875     }
   876 
   877     mem = pgp_memory_new();
   878     if (mem == NULL) {
   879         result = PEP_OUT_OF_MEMORY;
   880         goto unlock_netpgp;
   881     }
   882     pgp_memory_add(mem, (const uint8_t*)key_data, size);
   883 
   884     if (pgp_keyring_read_from_mem(netpgp.io, netpgp.pubring, netpgp.secring,
   885                                   _armoured(key_data, size, ARMOR_KEY_HEAD),
   886                                   mem) == 0){
   887         result = PEP_ILLEGAL_VALUE;
   888     }
   889 
   890     pgp_memory_free(mem);
   891 
   892     // save rings
   893     if (netpgp_save_pubring(&netpgp) &&
   894         netpgp_save_secring(&netpgp))
   895     {
   896         result = PEP_STATUS_OK;
   897     }else{
   898         result = PEP_UNKNOWN_ERROR;
   899     }
   900 
   901 unlock_netpgp:
   902     pthread_mutex_unlock(&netpgp_mutex);
   903 
   904     return result;
   905 }
   906 
   907 static PEP_STATUS _export_keydata(
   908     pgp_key_t *key,
   909     char **buffer,
   910     size_t *buflen
   911     )
   912 {
   913     PEP_STATUS result;
   914 	pgp_output_t *output;
   915     pgp_memory_t *mem;
   916 	pgp_setup_memory_write(&output, &mem, 128);
   917 
   918     if (mem == NULL || output == NULL) {
   919         return PEP_ILLEGAL_VALUE;
   920     }
   921 
   922     if (!pgp_write_xfer_key(output, key, 1)) {
   923         result = PEP_UNKNOWN_ERROR;
   924         goto free_mem;
   925     }
   926 
   927     *buffer = NULL;
   928     *buflen = pgp_mem_len(mem);
   929 
   930     // Allocate transferable buffer
   931     *buffer = malloc(*buflen + 1);
   932     assert(*buffer);
   933     if (*buffer == NULL) {
   934         result = PEP_OUT_OF_MEMORY;
   935         goto free_mem;
   936     }
   937 
   938     memcpy(*buffer, pgp_mem_data(mem), *buflen);
   939     (*buffer)[*buflen] = 0; // safeguard for naive users
   940 
   941     return PEP_STATUS_OK;
   942 
   943 free_mem :
   944 	pgp_teardown_memory_write(output, mem);
   945 
   946     return result;
   947 }
   948 
   949 PEP_STATUS pgp_export_keydata(
   950     PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
   951     )
   952 {
   953     pgp_key_t *key;
   954     uint8_t fpr[PGP_FINGERPRINT_SIZE];
   955     size_t fprlen;
   956 
   957     PEP_STATUS result;
   958     char *buffer;
   959     size_t buflen;
   960 
   961     assert(session);
   962     assert(fprstr);
   963     assert(key_data);
   964     assert(size);
   965 
   966     if (!session || !fprstr || !key_data || !size)
   967         return PEP_ILLEGAL_VALUE;
   968 
   969     if(pthread_mutex_lock(&netpgp_mutex)){
   970         return PEP_UNKNOWN_ERROR;
   971     }
   972 
   973     if (str_to_fpr(fprstr, fpr, &fprlen)) {
   974         unsigned from = 0;
   975 
   976         if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
   977                                                 fpr, fprlen, &from,
   978                                                 NULL,0,0)) == NULL) {
   979             result = PEP_KEY_NOT_FOUND;
   980             goto unlock_netpgp;
   981         }
   982     }else{
   983         result = PEP_OUT_OF_MEMORY;
   984         goto unlock_netpgp;
   985     }
   986 
   987     result = _export_keydata(key, &buffer, &buflen);
   988 
   989     if(result == PEP_STATUS_OK)
   990     {
   991         *key_data = buffer;
   992         *size = buflen;
   993         result = PEP_STATUS_OK;
   994     }
   995 
   996 unlock_netpgp:
   997     pthread_mutex_unlock(&netpgp_mutex);
   998 
   999     return result;
  1000 }
  1001 
  1002 struct HKP_answer {
  1003   char *memory;
  1004   size_t size;
  1005 };
  1006 
  1007 static size_t
  1008 HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
  1009 {
  1010   size_t realsize = size * nmemb;
  1011   struct HKP_answer *mem = (struct HKP_answer *)userp;
  1012 
  1013   mem->memory = realloc(mem->memory, mem->size + realsize + 1);
  1014   if(mem->memory == NULL) {
  1015     mem->size = 0;
  1016     return 0;
  1017   }
  1018 
  1019   memcpy(&(mem->memory[mem->size]), contents, realsize);
  1020   mem->size += realsize;
  1021   mem->memory[mem->size] = 0;
  1022 
  1023   return realsize;
  1024 }
  1025 
  1026 #define HKP_SERVER "http://keys.gnupg.net:11371"
  1027 // #define HKP_SERVER "http://127.0.0.1:11371"
  1028 
  1029 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1030 {
  1031     static const char *ks_cmd = HKP_SERVER
  1032                                 "/pks/lookup?"
  1033                                 "op=get&options=mr&exact=on&"
  1034                                 "search=";
  1035     char *encoded_pattern;
  1036     char *request = NULL;
  1037     struct HKP_answer answer;
  1038     CURLcode curlres;
  1039 
  1040     PEP_STATUS result;
  1041 
  1042     CURL *curl;
  1043 
  1044     assert(session);
  1045     assert(pattern);
  1046 
  1047     if (!session || !pattern )
  1048         return PEP_ILLEGAL_VALUE;
  1049 
  1050     if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  1051         return PEP_UNKNOWN_ERROR;
  1052     }
  1053 
  1054     result = curl_get_ctx(&curl);
  1055     if(result != PEP_STATUS_OK){
  1056         goto unlock_curl;
  1057     }
  1058 
  1059     encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
  1060     if(!encoded_pattern){
  1061         result = PEP_OUT_OF_MEMORY;
  1062         goto release_curl_ctx;
  1063     }
  1064 
  1065     if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
  1066         result = PEP_OUT_OF_MEMORY;
  1067         goto free_encoded_pattern;
  1068     }
  1069 
  1070     //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
  1071     stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
  1072 
  1073     curl_easy_setopt(curl, CURLOPT_URL,request);
  1074 
  1075     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
  1076 
  1077     answer.memory = NULL;
  1078     answer.size = 0;
  1079     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
  1080 
  1081     curlres = curl_easy_perform(curl);
  1082     if(curlres != CURLE_OK) {
  1083         result = PEP_GET_KEY_FAILED;
  1084         goto free_request;
  1085     }
  1086 
  1087     if(!answer.memory || !answer.size) {
  1088         result = PEP_OUT_OF_MEMORY;
  1089         goto free_request;
  1090     }
  1091 
  1092     result = pgp_import_keydata(session,
  1093                                 answer.memory,
  1094                                 answer.size);
  1095 
  1096 free_answer:
  1097     free(answer.memory);
  1098 free_request:
  1099     free(request);
  1100 free_encoded_pattern:
  1101     curl_free(encoded_pattern);
  1102 release_curl_ctx:
  1103     curl_release_ctx(&curl);
  1104 unlock_curl:
  1105     pthread_mutex_unlock(&session->ctx.curl_mutex);
  1106 
  1107     return result;
  1108 }
  1109 
  1110 typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  1111 
  1112 static PEP_STATUS find_keys_do(
  1113         const char *pattern, find_key_cb_t cb, void* cb_arg)
  1114 {
  1115     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1116     size_t length;
  1117     pgp_key_t *key;
  1118 
  1119     PEP_STATUS result;
  1120 
  1121     // Try find a fingerprint in pattern
  1122     if (str_to_fpr(pattern, fpr, &length)) {
  1123         unsigned from = 0;
  1124 
  1125 
  1126         // Only one fingerprint can match
  1127         if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  1128                         netpgp.io,
  1129                         (pgp_keyring_t *)netpgp.pubring,
  1130                         (const uint8_t *)fpr, length,
  1131                         &from,
  1132                         NULL, 0, 0)) == NULL) {
  1133 
  1134             return PEP_KEY_NOT_FOUND;
  1135         }
  1136 
  1137         result = cb(cb_arg, key);
  1138 
  1139     } else {
  1140         // Search by name for pattern. Can match many.
  1141         unsigned from = 0;
  1142         result = PEP_KEY_NOT_FOUND;
  1143         while((key = (pgp_key_t *)pgp_getnextkeybyname(
  1144                         netpgp.io,
  1145                         (pgp_keyring_t *)netpgp.pubring,
  1146 			            (const char *)pattern,
  1147                         &from)) != NULL) {
  1148 
  1149             result = cb(cb_arg, key);
  1150             if (result != PEP_STATUS_OK)
  1151                 break;
  1152 
  1153             from++;
  1154         }
  1155     }
  1156 
  1157     return result;
  1158 }
  1159 
  1160 static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  1161 {
  1162     stringlist_t **keylist = arg;
  1163     char *newfprstr = NULL;
  1164 
  1165     fpr_to_str(&newfprstr,
  1166                key->pubkeyfpr.fingerprint,
  1167                key->pubkeyfpr.length);
  1168 
  1169     if (newfprstr == NULL) {
  1170         return PEP_OUT_OF_MEMORY;
  1171     } else {
  1172 
  1173         stringlist_add(*keylist, newfprstr);
  1174         free(newfprstr);
  1175         if (*keylist == NULL) {
  1176             return PEP_OUT_OF_MEMORY;
  1177         }
  1178     }
  1179     return PEP_STATUS_OK;
  1180 }
  1181 
  1182 static PEP_STATUS add_secret_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  1183 {
  1184     if (pgp_is_key_secret(key)) {
  1185         stringlist_t **keylist = arg;
  1186         char *newfprstr = NULL;
  1187 
  1188         fpr_to_str(&newfprstr,
  1189                 key->pubkeyfpr.fingerprint,
  1190                 key->pubkeyfpr.length);
  1191 
  1192         if (newfprstr == NULL) {
  1193             return PEP_OUT_OF_MEMORY;
  1194         } else {
  1195             stringlist_add(*keylist, newfprstr);
  1196             free(newfprstr);
  1197             if (*keylist == NULL) {
  1198                 return PEP_OUT_OF_MEMORY;
  1199             }
  1200         }
  1201     }
  1202     return PEP_STATUS_OK;
  1203 }
  1204 
  1205 static PEP_STATUS add_keyinfo_to_stringpair_list(void* arg, pgp_key_t *key) {
  1206     stringpair_list_t** keyinfo_list = (stringpair_list_t**)arg;
  1207     stringpair_t* pair = NULL;
  1208     char* id_fpr = NULL;
  1209     char* primary_userid = (char*)pgp_key_get_primary_userid(key);
  1210 
  1211 // Unused:
  1212 //    bool key_revoked = false;
  1213 
  1214 //    PEP_STATUS key_status = pgp_key_revoked(session, id_fpr, &key_revoked);
  1215 
  1216 //    if (key_revoked || key_status == PEP_GET_KEY_FAILED)
  1217 //        return PEP_STATUS_OK; // we just move on
  1218 
  1219     fpr_to_str(&id_fpr, key->pubkeyfpr.fingerprint,
  1220                 key->pubkeyfpr.length);
  1221 
  1222     pair = new_stringpair(id_fpr, primary_userid);
  1223 
  1224     if (pair == NULL)
  1225         return PEP_OUT_OF_MEMORY;
  1226 
  1227     *keyinfo_list = stringpair_list_add(*keyinfo_list, pair);
  1228     free(id_fpr);
  1229     if (*keyinfo_list == NULL)
  1230         return PEP_OUT_OF_MEMORY;
  1231     return PEP_STATUS_OK;
  1232 }
  1233 
  1234 PEP_STATUS pgp_find_keys(
  1235     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1236     )
  1237 {
  1238     stringlist_t *_keylist, *_k;
  1239 
  1240     PEP_STATUS result;
  1241 
  1242     assert(session);
  1243     assert(pattern);
  1244     assert(keylist);
  1245 
  1246     if (!session || !pattern || !keylist )
  1247     {
  1248         return PEP_ILLEGAL_VALUE;
  1249     }
  1250 
  1251     if (pthread_mutex_lock(&netpgp_mutex))
  1252     {
  1253         return PEP_UNKNOWN_ERROR;
  1254     }
  1255 
  1256     *keylist = NULL;
  1257     _keylist = new_stringlist(NULL);
  1258     if (_keylist == NULL) {
  1259         result = PEP_OUT_OF_MEMORY;
  1260         goto unlock_netpgp;
  1261     }
  1262     _k = _keylist;
  1263 
  1264     result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  1265 
  1266     if (result == PEP_STATUS_OK) {
  1267         *keylist = _keylist;
  1268         // Transfer ownership, no free
  1269         goto unlock_netpgp;
  1270     }
  1271 
  1272 free_keylist:
  1273     free_stringlist(_keylist);
  1274 
  1275 unlock_netpgp:
  1276     pthread_mutex_unlock(&netpgp_mutex);
  1277 
  1278     return result;
  1279 }
  1280 
  1281 #define HKP_REQ_PREFIX "keytext="
  1282 #define HKP_REQ_PREFIX_LEN 8
  1283 
  1284 static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
  1285 {
  1286     char *buffer = NULL;
  1287     size_t buflen = 0;
  1288     PEP_STATUS result;
  1289     stringlist_t *encoded_keys;
  1290     encoded_keys = (stringlist_t*)arg;
  1291 
  1292     result = _export_keydata(key, &buffer, &buflen);
  1293 
  1294     if(result == PEP_STATUS_OK){
  1295         char *encoded_key = curl_escape(buffer, (int)buflen);
  1296         if(!encoded_key){
  1297             result = PEP_OUT_OF_MEMORY;
  1298             goto free_buffer;
  1299         }
  1300         size_t encoded_key_len = strlen(encoded_key);
  1301 
  1302         char *request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
  1303         if(!request){
  1304             result = PEP_OUT_OF_MEMORY;
  1305             goto free_encoded_key;
  1306         }
  1307 
  1308         memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
  1309         memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
  1310         request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
  1311 
  1312         if(!stringlist_add(encoded_keys, request)){
  1313             free(request);
  1314             result = PEP_OUT_OF_MEMORY;
  1315         }
  1316 
  1317         free(request);
  1318 
  1319 free_encoded_key:
  1320         curl_free(encoded_key);
  1321 
  1322 free_buffer:
  1323         free(buffer);
  1324     }
  1325 
  1326     return result;
  1327 }
  1328 
  1329 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1330 {
  1331     static const char *ks_cmd = HKP_SERVER "/pks/add";
  1332 
  1333     PEP_STATUS result;
  1334     CURL *curl = NULL;
  1335 
  1336     assert(session);
  1337     assert(pattern);
  1338 
  1339     if (!session || !pattern )
  1340         return PEP_ILLEGAL_VALUE;
  1341 
  1342     stringlist_t *encoded_keys = new_stringlist(NULL);
  1343     assert(encoded_keys);
  1344     if (encoded_keys == NULL) {
  1345         return PEP_OUT_OF_MEMORY;
  1346     }
  1347 
  1348     if(pthread_mutex_lock(&netpgp_mutex)){
  1349         result = PEP_UNKNOWN_ERROR;
  1350         goto free_encoded_keys;
  1351     }
  1352 
  1353     result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  1354 
  1355     pthread_mutex_unlock(&netpgp_mutex);
  1356 
  1357     if(result != PEP_STATUS_OK){
  1358         goto free_encoded_keys;
  1359     }
  1360 
  1361     if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  1362         result = PEP_UNKNOWN_ERROR;
  1363         goto free_encoded_keys;
  1364     }
  1365 
  1366     result = curl_get_ctx(&curl);
  1367     if(result != PEP_STATUS_OK){
  1368         goto unlock_curl;
  1369     }
  1370 
  1371     if(result == PEP_STATUS_OK){
  1372         CURLcode curlres;
  1373 
  1374         for (const stringlist_t *post = encoded_keys; post != NULL; post = post->next) {
  1375             assert(post->value);
  1376 
  1377             curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
  1378             curl_easy_setopt(curl, CURLOPT_POST, 1L);
  1379             curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
  1380             curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
  1381 
  1382             // Uncomment if debugging
  1383             // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  1384 
  1385             curlres = curl_easy_perform(curl);
  1386 
  1387             if(curlres != CURLE_OK) {
  1388 
  1389                 result = PEP_CANNOT_SEND_KEY;
  1390                 goto release_curl_ctx;
  1391             }
  1392         }
  1393     }
  1394 
  1395 release_curl_ctx:
  1396     curl_release_ctx(&curl);
  1397 unlock_curl:
  1398     pthread_mutex_unlock(&session->ctx.curl_mutex);
  1399 free_encoded_keys:
  1400     free_stringlist(encoded_keys);
  1401 
  1402     return result;
  1403 }
  1404 
  1405 
  1406 PEP_STATUS pgp_get_key_rating(
  1407     PEP_SESSION session,
  1408     const char *fprstr,
  1409     PEP_comm_type *comm_type
  1410     )
  1411 {
  1412     pgp_key_t *key;
  1413     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1414     unsigned from = 0;
  1415     size_t length;
  1416 
  1417 
  1418     PEP_STATUS status = PEP_STATUS_OK;
  1419 
  1420     assert(session);
  1421     assert(fprstr);
  1422     assert(comm_type);
  1423 
  1424     if (!session || !fprstr || !comm_type )
  1425         return PEP_ILLEGAL_VALUE;
  1426 
  1427     *comm_type = PEP_ct_unknown;
  1428 
  1429     if(pthread_mutex_lock(&netpgp_mutex)){
  1430         return PEP_UNKNOWN_ERROR;
  1431     }
  1432 
  1433     if (!str_to_fpr(fprstr, fpr, &length)) {
  1434         status = PEP_ILLEGAL_VALUE;
  1435         goto unlock_netpgp;
  1436     }
  1437 
  1438     key = pgp_getkeybyfpr(
  1439            netpgp.io,
  1440            netpgp.pubring,
  1441            fpr, length, &from, NULL,0,0);
  1442 
  1443     if(key == NULL)
  1444     {
  1445         status = PEP_KEY_NOT_FOUND;
  1446         goto unlock_netpgp;
  1447     }
  1448 
  1449     switch(pgp_key_get_rating(key)){
  1450 	case PGP_VALID:
  1451         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1452         break;
  1453     case PGP_WEAK:
  1454         *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1455         break;
  1456     case PGP_TOOSHORT:
  1457         *comm_type = PEP_ct_key_too_short;
  1458         break;
  1459 	case PGP_INVALID:
  1460         *comm_type = PEP_ct_key_b0rken;
  1461         break;
  1462 	case PGP_EXPIRED:
  1463         *comm_type = PEP_ct_key_expired;
  1464         break;
  1465     case PGP_REVOKED:
  1466         *comm_type = PEP_ct_key_revoked;
  1467         break;
  1468     default:
  1469         break;
  1470     }
  1471 
  1472 unlock_netpgp:
  1473     pthread_mutex_unlock(&netpgp_mutex);
  1474 
  1475     return status;
  1476 }
  1477 
  1478 PEP_STATUS pgp_renew_key(
  1479         PEP_SESSION session,
  1480         const char *fprstr,
  1481         const timestamp *ts
  1482     )
  1483 {
  1484     pgp_key_t *pkey;
  1485     pgp_key_t *skey;
  1486     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1487     size_t length;
  1488     unsigned from = 0;
  1489     time_t duration;
  1490     const uint8_t *primid;
  1491 
  1492     PEP_STATUS status = PEP_STATUS_OK;
  1493 
  1494     assert(session);
  1495     assert(fprstr);
  1496 
  1497     if (!session || !fprstr )
  1498         return PEP_ILLEGAL_VALUE;
  1499 
  1500     if(ts)
  1501     {
  1502         time_t    now, when;
  1503         now = time(NULL);
  1504         when = mktime((struct tm*)ts);
  1505         if(now && when && when > now){
  1506             duration = when - now;
  1507         }else{
  1508             return PEP_ILLEGAL_VALUE;
  1509         }
  1510     }else{
  1511         /* Default 1 year from now */
  1512         duration = 365*24*3600;
  1513     }
  1514 
  1515     if(pthread_mutex_lock(&netpgp_mutex)){
  1516         return PEP_UNKNOWN_ERROR;
  1517     }
  1518 
  1519 
  1520     if (!str_to_fpr(fprstr, fpr, &length)) {
  1521         status = PEP_ILLEGAL_VALUE;
  1522         goto unlock_netpgp;
  1523     }
  1524 
  1525     pkey = pgp_getkeybyfpr(
  1526                           netpgp.io,
  1527                           netpgp.pubring,
  1528                           fpr, length, &from, NULL,
  1529                           1, 0); /* reject revoked, accept expired */
  1530 
  1531     if(pkey == NULL)
  1532     {
  1533         status = PEP_KEY_NOT_FOUND;
  1534         goto unlock_netpgp;
  1535     }
  1536 
  1537     from = 0;
  1538     skey = pgp_getkeybyfpr(
  1539                            netpgp.io,
  1540                            netpgp.secring,
  1541                            fpr, length, &from, NULL,
  1542                            1, 0); /* reject revoked, accept expired */
  1543 
  1544     if(skey == NULL)
  1545     {
  1546         status = PEP_KEY_NOT_FOUND;
  1547         goto unlock_netpgp;
  1548     }
  1549 
  1550     if((primid = pgp_key_get_primary_userid(skey)) == NULL)
  1551     {
  1552         status = PEP_KEY_HAS_AMBIG_NAME;
  1553         goto unlock_netpgp;
  1554     }
  1555 
  1556     // FIXME : renew in a more gentle way
  1557     if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
  1558     {
  1559         status = PEP_CANNOT_CREATE_KEY;
  1560         goto unlock_netpgp;
  1561     }
  1562 
  1563     // save rings
  1564     if (netpgp_save_pubring(&netpgp) &&
  1565         netpgp_save_secring(&netpgp))
  1566     {
  1567         status = PEP_STATUS_OK;
  1568     }else{
  1569         status = PEP_UNKNOWN_ERROR;
  1570     }
  1571 
  1572 unlock_netpgp:
  1573     pthread_mutex_unlock(&netpgp_mutex);
  1574 
  1575     return status;
  1576 }
  1577 
  1578 PEP_STATUS pgp_revoke_key(
  1579         PEP_SESSION session,
  1580         const char *fprstr,
  1581         const char *reason
  1582     )
  1583 {
  1584     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1585     size_t length;
  1586     unsigned from = 0;
  1587 
  1588     PEP_STATUS status = PEP_STATUS_OK;
  1589 
  1590     assert(session);
  1591     assert(fprstr);
  1592 
  1593     if (!session || !fprstr)
  1594         return PEP_UNKNOWN_ERROR;
  1595 
  1596     if(pthread_mutex_lock(&netpgp_mutex)){
  1597         return PEP_UNKNOWN_ERROR;
  1598     }
  1599 
  1600     // FIXME : deduplicate that code w/ renew
  1601     if (!str_to_fpr(fprstr, fpr, &length)) {
  1602         status = PEP_ILLEGAL_VALUE;
  1603         goto unlock_netpgp;
  1604     }
  1605 
  1606     pgp_key_t *pkey = pgp_getkeybyfpr(
  1607                            netpgp.io,
  1608                            netpgp.pubring,
  1609                            fpr, length, &from, NULL,
  1610                            1, 0); /* reject revoked, accept expired */
  1611 
  1612     if(pkey == NULL)
  1613     {
  1614         status = PEP_KEY_NOT_FOUND;
  1615         goto unlock_netpgp;
  1616     }
  1617 
  1618     from = 0;
  1619     pgp_key_t *skey = pgp_getkeybyfpr(
  1620                            netpgp.io,
  1621                            netpgp.secring,
  1622                            fpr, length, &from, NULL,
  1623                            1, 0); /* reject revoked, accept expired */
  1624 
  1625     if(skey == NULL)
  1626     {
  1627         status = PEP_KEY_NOT_FOUND;
  1628         goto unlock_netpgp;
  1629     }
  1630 
  1631     pgp_key_revoke(skey, pkey,
  1632                    0, /* no reason code specified */
  1633                    reason);
  1634 
  1635 unlock_netpgp:
  1636     pthread_mutex_unlock(&netpgp_mutex);
  1637 
  1638     return status;
  1639 }
  1640 
  1641 PEP_STATUS pgp_key_expired(
  1642         PEP_SESSION session,
  1643         const char *fprstr,
  1644         const time_t when,
  1645         bool *expired
  1646     )
  1647 {
  1648     PEP_STATUS status = PEP_STATUS_OK;
  1649     PEP_comm_type comm_type;
  1650 
  1651     assert(session);
  1652     assert(fprstr);
  1653     assert(expired);
  1654 
  1655     if (!session || !fprstr || !expired)
  1656         return PEP_UNKNOWN_ERROR;
  1657 
  1658     // TODO : take "when" in account
  1659 
  1660     *expired = false;
  1661 
  1662     status = pgp_get_key_rating(session, fprstr, &comm_type);
  1663 
  1664     if (status != PEP_STATUS_OK)
  1665         return status;
  1666 
  1667     if (comm_type == PEP_ct_key_expired){
  1668         *expired = true;
  1669     }
  1670 
  1671     return PEP_STATUS_OK;
  1672 }
  1673 
  1674 PEP_STATUS pgp_key_revoked(
  1675         PEP_SESSION session,
  1676         const char *fprstr,
  1677         bool *revoked
  1678     )
  1679 {
  1680     PEP_STATUS status = PEP_STATUS_OK;
  1681     PEP_comm_type comm_type;
  1682 
  1683     assert(session);
  1684     assert(fprstr);
  1685     assert(revoked);
  1686 
  1687     *revoked = false;
  1688 
  1689     status = pgp_get_key_rating(session, fprstr, &comm_type);
  1690 
  1691     if (status != PEP_STATUS_OK)
  1692         return status;
  1693 
  1694     if (comm_type == PEP_ct_key_revoked){
  1695         *revoked = true;
  1696     }
  1697 
  1698     return PEP_STATUS_OK;
  1699 }
  1700 
  1701 PEP_STATUS pgp_key_created(
  1702         PEP_SESSION session,
  1703         const char *fprstr,
  1704         time_t *created
  1705     )
  1706 {
  1707     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1708     pgp_key_t *key;
  1709     size_t length;
  1710     unsigned from = 0;
  1711 
  1712     PEP_STATUS status = PEP_STATUS_OK;
  1713 
  1714     assert(session);
  1715     assert(fprstr);
  1716     assert(created);
  1717 
  1718     if (!session || !fprstr || !created)
  1719         return PEP_UNKNOWN_ERROR;
  1720 
  1721     *created = 0;
  1722 
  1723     if(pthread_mutex_lock(&netpgp_mutex)){
  1724         return PEP_UNKNOWN_ERROR;
  1725     }
  1726 
  1727     if (!str_to_fpr(fprstr, fpr, &length)) {
  1728         status = PEP_ILLEGAL_VALUE;
  1729         goto unlock_netpgp;
  1730     }
  1731 
  1732     key = pgp_getkeybyfpr(
  1733            netpgp.io,
  1734            netpgp.pubring,
  1735            fpr, length, &from, NULL,0,0);
  1736 
  1737     if (key)
  1738     {
  1739         *created = (time_t) key->key.pubkey.birthtime;
  1740     }
  1741     else
  1742     {
  1743         status = PEP_KEY_NOT_FOUND;
  1744         goto unlock_netpgp;
  1745     }
  1746 
  1747 
  1748 
  1749 unlock_netpgp:
  1750     pthread_mutex_unlock(&netpgp_mutex);
  1751 
  1752     return status;
  1753 }
  1754 
  1755 
  1756 PEP_STATUS pgp_list_keyinfo(
  1757         PEP_SESSION session, const char* pattern, stringpair_list_t** keyinfo_list)
  1758 {
  1759 
  1760     if (!session || !keyinfo_list)
  1761         return PEP_UNKNOWN_ERROR;
  1762 
  1763     if (pthread_mutex_lock(&netpgp_mutex))
  1764     {
  1765         return PEP_UNKNOWN_ERROR;
  1766     }
  1767 
  1768 // Unused:
  1769 //    pgp_key_t *key;
  1770 
  1771     PEP_STATUS result;
  1772 
  1773     result = find_keys_do(pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  1774 
  1775     if (!keyinfo_list)
  1776         result = PEP_KEY_NOT_FOUND;
  1777 
  1778 unlock_netpgp:
  1779     pthread_mutex_unlock(&netpgp_mutex);
  1780 
  1781     return result;
  1782 }
  1783 
  1784 /* copied from find_keys, but we need to use a callback that filters. */
  1785 PEP_STATUS pgp_find_private_keys(
  1786     PEP_SESSION session, const char *pattern, stringlist_t **keylist)
  1787 {
  1788     stringlist_t *_keylist, *_k;
  1789 
  1790     PEP_STATUS result;
  1791 
  1792     assert(session);
  1793     assert(pattern);
  1794     assert(keylist);
  1795 
  1796     if (!session || !pattern || !keylist )
  1797     {
  1798         return PEP_ILLEGAL_VALUE;
  1799     }
  1800 
  1801     if (pthread_mutex_lock(&netpgp_mutex))
  1802     {
  1803         return PEP_UNKNOWN_ERROR;
  1804     }
  1805 
  1806     *keylist = NULL;
  1807     _keylist = new_stringlist(NULL);
  1808     if (_keylist == NULL) {
  1809         result = PEP_OUT_OF_MEMORY;
  1810         goto unlock_netpgp;
  1811     }
  1812     _k = _keylist;
  1813 
  1814     result = find_keys_do(pattern, &add_secret_key_fpr_to_stringlist, &_k);
  1815 
  1816     if (result == PEP_STATUS_OK) {
  1817         *keylist = _keylist;
  1818         // Transfer ownership, no free
  1819         goto unlock_netpgp;
  1820     }
  1821 
  1822 free_keylist:
  1823     free_stringlist(_keylist);
  1824 
  1825 unlock_netpgp:
  1826     pthread_mutex_unlock(&netpgp_mutex);
  1827 
  1828     return result;
  1829 }
  1830 
  1831 PEP_STATUS pgp_contains_priv_key(
  1832     PEP_SESSION session,
  1833     const char *fpr,
  1834     bool *has_private) {
  1835     stringlist_t* keylist = NULL;
  1836     PEP_STATUS status = pgp_find_private_keys(session, fpr, &keylist);
  1837     if (status == PEP_STATUS_OK && keylist) {
  1838         free_stringlist(keylist);
  1839         *has_private = true;
  1840     }
  1841     else {
  1842         has_private = false;
  1843     }
  1844     return status;
  1845 }