src/pgp_netpgp.c
author Krista Bennett <krista@pep-project.org>
Wed, 15 Mar 2017 18:02:46 +0100
changeset 1674 5639f969866a
parent 1559 c6506bc6a0df
child 1677 e02c53c94550
child 1678 0f63e86eda03
permissions -rw-r--r--
Added pgp_encrypt_only stubs for NetPGP
     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_encrypt_only(
   691         PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   692         size_t psize, char **ctext, size_t *csize
   693     )
   694 {
   695     return PEP_UNKNOWN_ERROR; // FIXME: Unimplemented!
   696 }
   697 
   698 
   699 PEP_STATUS pgp_generate_keypair(
   700     PEP_SESSION session, pEp_identity *identity
   701     )
   702 {
   703     pgp_key_t	newseckey;
   704     pgp_key_t	*newpubkey;
   705 
   706     PEP_STATUS result;
   707     char newid[1024];
   708     const char *hashalg;
   709     const char *cipher;
   710 
   711     assert(session);
   712     assert(identity);
   713     assert(identity->address);
   714     assert(identity->fpr == NULL);
   715     assert(identity->username);
   716 
   717     if(!session || !identity ||
   718        !identity->address || identity->fpr || !identity->username)
   719         return PEP_ILLEGAL_VALUE;
   720 
   721     if(pthread_mutex_lock(&netpgp_mutex)){
   722         return PEP_UNKNOWN_ERROR;
   723     }
   724 
   725     if(snprintf(newid, sizeof(newid),
   726         "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
   727         result =  PEP_BUFFER_TOO_SMALL;
   728         goto unlock_netpgp;
   729     }
   730 
   731     hashalg = netpgp_getvar(&netpgp, "hash");
   732     cipher = netpgp_getvar(&netpgp, "cipher");
   733 
   734     bzero(&newseckey, sizeof(newseckey));
   735 
   736     // Generate the key
   737     if (!pgp_rsa_generate_keypair(&newseckey, 4096, 65537UL, hashalg, cipher,
   738                                   (const uint8_t *) "", (const size_t) 0))
   739     {
   740         result = PEP_CANNOT_CREATE_KEY;
   741         goto free_seckey;
   742     }
   743 
   744     /* make a public key out of generated secret key */
   745     if((newpubkey = pgp_ensure_pubkey(
   746             netpgp.pubring,
   747             &newseckey.key.seckey.pubkey,
   748             newseckey.pubkeyid))==NULL)
   749     {
   750         result = PEP_OUT_OF_MEMORY;
   751         goto free_seckey;
   752     }
   753 
   754     // "Expire-Date: 1y\n";
   755     if (!pgp_add_selfsigned_userid(&newseckey, newpubkey,
   756                                   (uint8_t *)newid, 365*24*3600))
   757     {
   758         result = PEP_CANNOT_CREATE_KEY;
   759         goto delete_pubkey;
   760     }
   761 
   762     if (newpubkey == NULL)
   763     {
   764         result = PEP_OUT_OF_MEMORY;
   765         goto delete_pubkey;
   766     }
   767 
   768     // Append key to netpgp's rings (key ownership transfered)
   769     if (!pgp_keyring_add(netpgp.secring, &newseckey)){
   770         result = PEP_OUT_OF_MEMORY;
   771         goto delete_pubkey;
   772     }
   773 
   774     // save rings
   775     if (netpgp_save_pubring(&netpgp) && netpgp_save_secring(&netpgp))
   776     {
   777         char *fprstr = NULL;
   778         fpr_to_str(&fprstr,
   779                    newseckey.pubkeyfpr.fingerprint,
   780                    newseckey.pubkeyfpr.length);
   781 
   782         if (fprstr == NULL) {
   783             result = PEP_OUT_OF_MEMORY;
   784             goto pop_secring;
   785         }
   786 
   787         /* keys saved, pass fingerprint back */
   788         identity->fpr = fprstr;
   789         result = PEP_STATUS_OK;
   790 
   791         /* free nothing, everything transfered */
   792         goto unlock_netpgp;
   793     } else {
   794         /* XXX in case only pubring save succeed
   795          * pubring file is left as-is, but backup restore
   796          * could be attempted if such corner case matters */
   797         result = PEP_UNKNOWN_ERROR;
   798     }
   799 
   800 pop_secring:
   801     ((pgp_keyring_t *)netpgp.secring)->keyc--;
   802 delete_pubkey:
   803     pgp_deletekeybyfpr(netpgp.io,
   804                     (pgp_keyring_t *)netpgp.pubring,
   805                     newseckey.pubkeyfpr.fingerprint,
   806                     newseckey.pubkeyfpr.length);
   807 free_seckey:
   808     pgp_key_free(&newseckey);
   809 unlock_netpgp:
   810     pthread_mutex_unlock(&netpgp_mutex);
   811 
   812     return result;
   813 }
   814 
   815 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
   816 {
   817     uint8_t fpr[PGP_FINGERPRINT_SIZE];
   818     size_t length;
   819 
   820     PEP_STATUS result;
   821 
   822     assert(session);
   823     assert(fprstr);
   824 
   825     if (!session || !fprstr)
   826         return PEP_ILLEGAL_VALUE;
   827 
   828     if(pthread_mutex_lock(&netpgp_mutex)){
   829         return PEP_UNKNOWN_ERROR;
   830     }
   831 
   832     if (str_to_fpr(fprstr, fpr, &length)) {
   833         unsigned insec = pgp_deletekeybyfpr(netpgp.io,
   834                                 (pgp_keyring_t *)netpgp.secring,
   835                                 (const uint8_t *)fpr, length);
   836         unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
   837                                 (pgp_keyring_t *)netpgp.pubring,
   838                                 (const uint8_t *)fpr, length);
   839         if(!insec && !inpub){
   840             result = PEP_KEY_NOT_FOUND;
   841             goto unlock_netpgp;
   842         } else {
   843             result = PEP_STATUS_OK;
   844         }
   845     }else{
   846         result = PEP_OUT_OF_MEMORY;
   847         goto unlock_netpgp;
   848     }
   849 
   850     // save rings
   851     if (netpgp_save_pubring(&netpgp) &&
   852         netpgp_save_secring(&netpgp))
   853     {
   854         result = PEP_STATUS_OK;
   855     }else{
   856         result = PEP_UNKNOWN_ERROR;
   857     }
   858 
   859 unlock_netpgp:
   860     pthread_mutex_unlock(&netpgp_mutex);
   861 
   862     return result;
   863 }
   864 
   865 #define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----"_ENDL
   866 PEP_STATUS pgp_import_keydata(
   867         PEP_SESSION session,
   868         const char *key_data,
   869         size_t size
   870     )
   871 {
   872     pgp_memory_t *mem;
   873 
   874     PEP_STATUS result = PEP_STATUS_OK;
   875 
   876     assert(session);
   877     assert(key_data);
   878 
   879     if(!session || !key_data)
   880         return PEP_ILLEGAL_VALUE;
   881 
   882     if(pthread_mutex_lock(&netpgp_mutex)){
   883         return PEP_UNKNOWN_ERROR;
   884     }
   885 
   886     mem = pgp_memory_new();
   887     if (mem == NULL) {
   888         result = PEP_OUT_OF_MEMORY;
   889         goto unlock_netpgp;
   890     }
   891     pgp_memory_add(mem, (const uint8_t*)key_data, size);
   892 
   893     if (pgp_keyring_read_from_mem(netpgp.io, netpgp.pubring, netpgp.secring,
   894                                   _armoured(key_data, size, ARMOR_KEY_HEAD),
   895                                   mem) == 0){
   896         result = PEP_ILLEGAL_VALUE;
   897     }
   898 
   899     pgp_memory_free(mem);
   900 
   901     // save rings
   902     if (netpgp_save_pubring(&netpgp) &&
   903         netpgp_save_secring(&netpgp))
   904     {
   905         result = PEP_STATUS_OK;
   906     }else{
   907         result = PEP_UNKNOWN_ERROR;
   908     }
   909 
   910 unlock_netpgp:
   911     pthread_mutex_unlock(&netpgp_mutex);
   912 
   913     return result;
   914 }
   915 
   916 static PEP_STATUS _export_keydata(
   917     pgp_key_t *key,
   918     char **buffer,
   919     size_t *buflen
   920     )
   921 {
   922     PEP_STATUS result;
   923 	pgp_output_t *output;
   924     pgp_memory_t *mem;
   925 	pgp_setup_memory_write(&output, &mem, 128);
   926 
   927     if (mem == NULL || output == NULL) {
   928         return PEP_ILLEGAL_VALUE;
   929     }
   930 
   931     if (!pgp_write_xfer_key(output, key, 1)) {
   932         result = PEP_UNKNOWN_ERROR;
   933         goto free_mem;
   934     }
   935 
   936     *buffer = NULL;
   937     *buflen = pgp_mem_len(mem);
   938 
   939     // Allocate transferable buffer
   940     *buffer = malloc(*buflen + 1);
   941     assert(*buffer);
   942     if (*buffer == NULL) {
   943         result = PEP_OUT_OF_MEMORY;
   944         goto free_mem;
   945     }
   946 
   947     memcpy(*buffer, pgp_mem_data(mem), *buflen);
   948     (*buffer)[*buflen] = 0; // safeguard for naive users
   949 
   950     return PEP_STATUS_OK;
   951 
   952 free_mem :
   953 	pgp_teardown_memory_write(output, mem);
   954 
   955     return result;
   956 }
   957 
   958 PEP_STATUS pgp_export_keydata(
   959     PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
   960     )
   961 {
   962     pgp_key_t *key;
   963     uint8_t fpr[PGP_FINGERPRINT_SIZE];
   964     size_t fprlen;
   965 
   966     PEP_STATUS result;
   967     char *buffer;
   968     size_t buflen;
   969 
   970     assert(session);
   971     assert(fprstr);
   972     assert(key_data);
   973     assert(size);
   974 
   975     if (!session || !fprstr || !key_data || !size)
   976         return PEP_ILLEGAL_VALUE;
   977 
   978     if(pthread_mutex_lock(&netpgp_mutex)){
   979         return PEP_UNKNOWN_ERROR;
   980     }
   981 
   982     if (str_to_fpr(fprstr, fpr, &fprlen)) {
   983         unsigned from = 0;
   984 
   985         if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
   986                                                 fpr, fprlen, &from,
   987                                                 NULL,0,0)) == NULL) {
   988             result = PEP_KEY_NOT_FOUND;
   989             goto unlock_netpgp;
   990         }
   991     }else{
   992         result = PEP_OUT_OF_MEMORY;
   993         goto unlock_netpgp;
   994     }
   995 
   996     result = _export_keydata(key, &buffer, &buflen);
   997 
   998     if(result == PEP_STATUS_OK)
   999     {
  1000         *key_data = buffer;
  1001         *size = buflen;
  1002         result = PEP_STATUS_OK;
  1003     }
  1004 
  1005 unlock_netpgp:
  1006     pthread_mutex_unlock(&netpgp_mutex);
  1007 
  1008     return result;
  1009 }
  1010 
  1011 struct HKP_answer {
  1012   char *memory;
  1013   size_t size;
  1014 };
  1015 
  1016 static size_t
  1017 HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
  1018 {
  1019   size_t realsize = size * nmemb;
  1020   struct HKP_answer *mem = (struct HKP_answer *)userp;
  1021 
  1022   mem->memory = realloc(mem->memory, mem->size + realsize + 1);
  1023   if(mem->memory == NULL) {
  1024     mem->size = 0;
  1025     return 0;
  1026   }
  1027 
  1028   memcpy(&(mem->memory[mem->size]), contents, realsize);
  1029   mem->size += realsize;
  1030   mem->memory[mem->size] = 0;
  1031 
  1032   return realsize;
  1033 }
  1034 
  1035 #define HKP_SERVER "http://keys.gnupg.net:11371"
  1036 // #define HKP_SERVER "http://127.0.0.1:11371"
  1037 
  1038 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1039 {
  1040     static const char *ks_cmd = HKP_SERVER
  1041                                 "/pks/lookup?"
  1042                                 "op=get&options=mr&exact=on&"
  1043                                 "search=";
  1044     char *encoded_pattern;
  1045     char *request = NULL;
  1046     struct HKP_answer answer;
  1047     CURLcode curlres;
  1048 
  1049     PEP_STATUS result;
  1050 
  1051     CURL *curl;
  1052 
  1053     assert(session);
  1054     assert(pattern);
  1055 
  1056     if (!session || !pattern )
  1057         return PEP_ILLEGAL_VALUE;
  1058 
  1059     if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  1060         return PEP_UNKNOWN_ERROR;
  1061     }
  1062 
  1063     result = curl_get_ctx(&curl);
  1064     if(result != PEP_STATUS_OK){
  1065         goto unlock_curl;
  1066     }
  1067 
  1068     encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
  1069     if(!encoded_pattern){
  1070         result = PEP_OUT_OF_MEMORY;
  1071         goto release_curl_ctx;
  1072     }
  1073 
  1074     if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
  1075         result = PEP_OUT_OF_MEMORY;
  1076         goto free_encoded_pattern;
  1077     }
  1078 
  1079     //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
  1080     stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
  1081 
  1082     curl_easy_setopt(curl, CURLOPT_URL,request);
  1083 
  1084     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
  1085 
  1086     answer.memory = NULL;
  1087     answer.size = 0;
  1088     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
  1089 
  1090     curlres = curl_easy_perform(curl);
  1091     if(curlres != CURLE_OK) {
  1092         result = PEP_GET_KEY_FAILED;
  1093         goto free_request;
  1094     }
  1095 
  1096     if(!answer.memory || !answer.size) {
  1097         result = PEP_OUT_OF_MEMORY;
  1098         goto free_request;
  1099     }
  1100 
  1101     result = pgp_import_keydata(session,
  1102                                 answer.memory,
  1103                                 answer.size);
  1104 
  1105 free_answer:
  1106     free(answer.memory);
  1107 free_request:
  1108     free(request);
  1109 free_encoded_pattern:
  1110     curl_free(encoded_pattern);
  1111 release_curl_ctx:
  1112     curl_release_ctx(&curl);
  1113 unlock_curl:
  1114     pthread_mutex_unlock(&session->ctx.curl_mutex);
  1115 
  1116     return result;
  1117 }
  1118 
  1119 typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  1120 
  1121 static PEP_STATUS find_keys_do(
  1122         const char *pattern, find_key_cb_t cb, void* cb_arg)
  1123 {
  1124     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1125     size_t length;
  1126     pgp_key_t *key;
  1127 
  1128     PEP_STATUS result;
  1129 
  1130     // Try find a fingerprint in pattern
  1131     if (str_to_fpr(pattern, fpr, &length)) {
  1132         unsigned from = 0;
  1133 
  1134 
  1135         // Only one fingerprint can match
  1136         if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  1137                         netpgp.io,
  1138                         (pgp_keyring_t *)netpgp.pubring,
  1139                         (const uint8_t *)fpr, length,
  1140                         &from,
  1141                         NULL, 0, 0)) == NULL) {
  1142 
  1143             return PEP_KEY_NOT_FOUND;
  1144         }
  1145 
  1146         result = cb(cb_arg, key);
  1147 
  1148     } else {
  1149         // Search by name for pattern. Can match many.
  1150         unsigned from = 0;
  1151         result = PEP_KEY_NOT_FOUND;
  1152         while((key = (pgp_key_t *)pgp_getnextkeybyname(
  1153                         netpgp.io,
  1154                         (pgp_keyring_t *)netpgp.pubring,
  1155 			            (const char *)pattern,
  1156                         &from)) != NULL) {
  1157 
  1158             result = cb(cb_arg, key);
  1159             if (result != PEP_STATUS_OK)
  1160                 break;
  1161 
  1162             from++;
  1163         }
  1164     }
  1165 
  1166     return result;
  1167 }
  1168 
  1169 static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  1170 {
  1171     stringlist_t **keylist = arg;
  1172     char *newfprstr = NULL;
  1173 
  1174     fpr_to_str(&newfprstr,
  1175                key->pubkeyfpr.fingerprint,
  1176                key->pubkeyfpr.length);
  1177 
  1178     if (newfprstr == NULL) {
  1179         return PEP_OUT_OF_MEMORY;
  1180     } else {
  1181 
  1182         stringlist_add(*keylist, newfprstr);
  1183         free(newfprstr);
  1184         if (*keylist == NULL) {
  1185             return PEP_OUT_OF_MEMORY;
  1186         }
  1187     }
  1188     return PEP_STATUS_OK;
  1189 }
  1190 
  1191 static PEP_STATUS add_secret_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  1192 {
  1193     if (pgp_is_key_secret(key)) {
  1194         stringlist_t **keylist = arg;
  1195         char *newfprstr = NULL;
  1196 
  1197         fpr_to_str(&newfprstr,
  1198                 key->pubkeyfpr.fingerprint,
  1199                 key->pubkeyfpr.length);
  1200 
  1201         if (newfprstr == NULL) {
  1202             return PEP_OUT_OF_MEMORY;
  1203         } else {
  1204             stringlist_add(*keylist, newfprstr);
  1205             free(newfprstr);
  1206             if (*keylist == NULL) {
  1207                 return PEP_OUT_OF_MEMORY;
  1208             }
  1209         }
  1210     }
  1211     return PEP_STATUS_OK;
  1212 }
  1213 
  1214 static PEP_STATUS add_keyinfo_to_stringpair_list(void* arg, pgp_key_t *key) {
  1215     stringpair_list_t** keyinfo_list = (stringpair_list_t**)arg;
  1216     stringpair_t* pair = NULL;
  1217     char* id_fpr = NULL;
  1218     char* primary_userid = (char*)pgp_key_get_primary_userid(key);
  1219 
  1220 // Unused:
  1221 //    bool key_revoked = false;
  1222 
  1223 //    PEP_STATUS key_status = pgp_key_revoked(session, id_fpr, &key_revoked);
  1224 
  1225 //    if (key_revoked || key_status == PEP_GET_KEY_FAILED)
  1226 //        return PEP_STATUS_OK; // we just move on
  1227 
  1228     fpr_to_str(&id_fpr, key->pubkeyfpr.fingerprint,
  1229                 key->pubkeyfpr.length);
  1230 
  1231     pair = new_stringpair(id_fpr, primary_userid);
  1232 
  1233     if (pair == NULL)
  1234         return PEP_OUT_OF_MEMORY;
  1235 
  1236     *keyinfo_list = stringpair_list_add(*keyinfo_list, pair);
  1237     free(id_fpr);
  1238     if (*keyinfo_list == NULL)
  1239         return PEP_OUT_OF_MEMORY;
  1240     return PEP_STATUS_OK;
  1241 }
  1242 
  1243 PEP_STATUS pgp_find_keys(
  1244     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1245     )
  1246 {
  1247     stringlist_t *_keylist, *_k;
  1248 
  1249     PEP_STATUS result;
  1250 
  1251     assert(session);
  1252     assert(pattern);
  1253     assert(keylist);
  1254 
  1255     if (!session || !pattern || !keylist )
  1256     {
  1257         return PEP_ILLEGAL_VALUE;
  1258     }
  1259 
  1260     if (pthread_mutex_lock(&netpgp_mutex))
  1261     {
  1262         return PEP_UNKNOWN_ERROR;
  1263     }
  1264 
  1265     *keylist = NULL;
  1266     _keylist = new_stringlist(NULL);
  1267     if (_keylist == NULL) {
  1268         result = PEP_OUT_OF_MEMORY;
  1269         goto unlock_netpgp;
  1270     }
  1271     _k = _keylist;
  1272 
  1273     result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  1274 
  1275     if (result == PEP_STATUS_OK) {
  1276         *keylist = _keylist;
  1277         // Transfer ownership, no free
  1278         goto unlock_netpgp;
  1279     }
  1280 
  1281 free_keylist:
  1282     free_stringlist(_keylist);
  1283 
  1284 unlock_netpgp:
  1285     pthread_mutex_unlock(&netpgp_mutex);
  1286 
  1287     return result;
  1288 }
  1289 
  1290 #define HKP_REQ_PREFIX "keytext="
  1291 #define HKP_REQ_PREFIX_LEN 8
  1292 
  1293 static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
  1294 {
  1295     char *buffer = NULL;
  1296     size_t buflen = 0;
  1297     PEP_STATUS result;
  1298     stringlist_t *encoded_keys;
  1299     encoded_keys = (stringlist_t*)arg;
  1300 
  1301     result = _export_keydata(key, &buffer, &buflen);
  1302 
  1303     if(result == PEP_STATUS_OK){
  1304         char *encoded_key = curl_escape(buffer, (int)buflen);
  1305         if(!encoded_key){
  1306             result = PEP_OUT_OF_MEMORY;
  1307             goto free_buffer;
  1308         }
  1309         size_t encoded_key_len = strlen(encoded_key);
  1310 
  1311         char *request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
  1312         if(!request){
  1313             result = PEP_OUT_OF_MEMORY;
  1314             goto free_encoded_key;
  1315         }
  1316 
  1317         memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
  1318         memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
  1319         request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
  1320 
  1321         if(!stringlist_add(encoded_keys, request)){
  1322             free(request);
  1323             result = PEP_OUT_OF_MEMORY;
  1324         }
  1325 
  1326         free(request);
  1327 
  1328 free_encoded_key:
  1329         curl_free(encoded_key);
  1330 
  1331 free_buffer:
  1332         free(buffer);
  1333     }
  1334 
  1335     return result;
  1336 }
  1337 
  1338 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1339 {
  1340     static const char *ks_cmd = HKP_SERVER "/pks/add";
  1341 
  1342     PEP_STATUS result;
  1343     CURL *curl = NULL;
  1344 
  1345     assert(session);
  1346     assert(pattern);
  1347 
  1348     if (!session || !pattern )
  1349         return PEP_ILLEGAL_VALUE;
  1350 
  1351     stringlist_t *encoded_keys = new_stringlist(NULL);
  1352     assert(encoded_keys);
  1353     if (encoded_keys == NULL) {
  1354         return PEP_OUT_OF_MEMORY;
  1355     }
  1356 
  1357     if(pthread_mutex_lock(&netpgp_mutex)){
  1358         result = PEP_UNKNOWN_ERROR;
  1359         goto free_encoded_keys;
  1360     }
  1361 
  1362     result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  1363 
  1364     pthread_mutex_unlock(&netpgp_mutex);
  1365 
  1366     if(result != PEP_STATUS_OK){
  1367         goto free_encoded_keys;
  1368     }
  1369 
  1370     if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  1371         result = PEP_UNKNOWN_ERROR;
  1372         goto free_encoded_keys;
  1373     }
  1374 
  1375     result = curl_get_ctx(&curl);
  1376     if(result != PEP_STATUS_OK){
  1377         goto unlock_curl;
  1378     }
  1379 
  1380     if(result == PEP_STATUS_OK){
  1381         CURLcode curlres;
  1382 
  1383         for (const stringlist_t *post = encoded_keys; post != NULL; post = post->next) {
  1384             assert(post->value);
  1385 
  1386             curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
  1387             curl_easy_setopt(curl, CURLOPT_POST, 1L);
  1388             curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
  1389             curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
  1390 
  1391             // Uncomment if debugging
  1392             // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  1393 
  1394             curlres = curl_easy_perform(curl);
  1395 
  1396             if(curlres != CURLE_OK) {
  1397 
  1398                 result = PEP_CANNOT_SEND_KEY;
  1399                 goto release_curl_ctx;
  1400             }
  1401         }
  1402     }
  1403 
  1404 release_curl_ctx:
  1405     curl_release_ctx(&curl);
  1406 unlock_curl:
  1407     pthread_mutex_unlock(&session->ctx.curl_mutex);
  1408 free_encoded_keys:
  1409     free_stringlist(encoded_keys);
  1410 
  1411     return result;
  1412 }
  1413 
  1414 
  1415 PEP_STATUS pgp_get_key_rating(
  1416     PEP_SESSION session,
  1417     const char *fprstr,
  1418     PEP_comm_type *comm_type
  1419     )
  1420 {
  1421     pgp_key_t *key;
  1422     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1423     unsigned from = 0;
  1424     size_t length;
  1425 
  1426 
  1427     PEP_STATUS status = PEP_STATUS_OK;
  1428 
  1429     assert(session);
  1430     assert(fprstr);
  1431     assert(comm_type);
  1432 
  1433     if (!session || !fprstr || !comm_type )
  1434         return PEP_ILLEGAL_VALUE;
  1435 
  1436     *comm_type = PEP_ct_unknown;
  1437 
  1438     if(pthread_mutex_lock(&netpgp_mutex)){
  1439         return PEP_UNKNOWN_ERROR;
  1440     }
  1441 
  1442     if (!str_to_fpr(fprstr, fpr, &length)) {
  1443         status = PEP_ILLEGAL_VALUE;
  1444         goto unlock_netpgp;
  1445     }
  1446 
  1447     key = pgp_getkeybyfpr(
  1448            netpgp.io,
  1449            netpgp.pubring,
  1450            fpr, length, &from, NULL,0,0);
  1451 
  1452     if(key == NULL)
  1453     {
  1454         status = PEP_KEY_NOT_FOUND;
  1455         goto unlock_netpgp;
  1456     }
  1457 
  1458     switch(pgp_key_get_rating(key)){
  1459 	case PGP_VALID:
  1460         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1461         break;
  1462     case PGP_WEAK:
  1463         *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1464         break;
  1465     case PGP_TOOSHORT:
  1466         *comm_type = PEP_ct_key_too_short;
  1467         break;
  1468 	case PGP_INVALID:
  1469         *comm_type = PEP_ct_key_b0rken;
  1470         break;
  1471 	case PGP_EXPIRED:
  1472         *comm_type = PEP_ct_key_expired;
  1473         break;
  1474     case PGP_REVOKED:
  1475         *comm_type = PEP_ct_key_revoked;
  1476         break;
  1477     default:
  1478         break;
  1479     }
  1480 
  1481 unlock_netpgp:
  1482     pthread_mutex_unlock(&netpgp_mutex);
  1483 
  1484     return status;
  1485 }
  1486 
  1487 PEP_STATUS pgp_renew_key(
  1488         PEP_SESSION session,
  1489         const char *fprstr,
  1490         const timestamp *ts
  1491     )
  1492 {
  1493     pgp_key_t *pkey;
  1494     pgp_key_t *skey;
  1495     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1496     size_t length;
  1497     unsigned from = 0;
  1498     time_t duration;
  1499     const uint8_t *primid;
  1500 
  1501     PEP_STATUS status = PEP_STATUS_OK;
  1502 
  1503     assert(session);
  1504     assert(fprstr);
  1505 
  1506     if (!session || !fprstr )
  1507         return PEP_ILLEGAL_VALUE;
  1508 
  1509     if(ts)
  1510     {
  1511         time_t    now, when;
  1512         now = time(NULL);
  1513         when = mktime((struct tm*)ts);
  1514         if(now && when && when > now){
  1515             duration = when - now;
  1516         }else{
  1517             return PEP_ILLEGAL_VALUE;
  1518         }
  1519     }else{
  1520         /* Default 1 year from now */
  1521         duration = 365*24*3600;
  1522     }
  1523 
  1524     if(pthread_mutex_lock(&netpgp_mutex)){
  1525         return PEP_UNKNOWN_ERROR;
  1526     }
  1527 
  1528 
  1529     if (!str_to_fpr(fprstr, fpr, &length)) {
  1530         status = PEP_ILLEGAL_VALUE;
  1531         goto unlock_netpgp;
  1532     }
  1533 
  1534     pkey = pgp_getkeybyfpr(
  1535                           netpgp.io,
  1536                           netpgp.pubring,
  1537                           fpr, length, &from, NULL,
  1538                           1, 0); /* reject revoked, accept expired */
  1539 
  1540     if(pkey == NULL)
  1541     {
  1542         status = PEP_KEY_NOT_FOUND;
  1543         goto unlock_netpgp;
  1544     }
  1545 
  1546     from = 0;
  1547     skey = pgp_getkeybyfpr(
  1548                            netpgp.io,
  1549                            netpgp.secring,
  1550                            fpr, length, &from, NULL,
  1551                            1, 0); /* reject revoked, accept expired */
  1552 
  1553     if(skey == NULL)
  1554     {
  1555         status = PEP_KEY_NOT_FOUND;
  1556         goto unlock_netpgp;
  1557     }
  1558 
  1559     if((primid = pgp_key_get_primary_userid(skey)) == NULL)
  1560     {
  1561         status = PEP_KEY_HAS_AMBIG_NAME;
  1562         goto unlock_netpgp;
  1563     }
  1564 
  1565     // FIXME : renew in a more gentle way
  1566     if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
  1567     {
  1568         status = PEP_CANNOT_CREATE_KEY;
  1569         goto unlock_netpgp;
  1570     }
  1571 
  1572     // save rings
  1573     if (netpgp_save_pubring(&netpgp) &&
  1574         netpgp_save_secring(&netpgp))
  1575     {
  1576         status = PEP_STATUS_OK;
  1577     }else{
  1578         status = PEP_UNKNOWN_ERROR;
  1579     }
  1580 
  1581 unlock_netpgp:
  1582     pthread_mutex_unlock(&netpgp_mutex);
  1583 
  1584     return status;
  1585 }
  1586 
  1587 PEP_STATUS pgp_revoke_key(
  1588         PEP_SESSION session,
  1589         const char *fprstr,
  1590         const char *reason
  1591     )
  1592 {
  1593     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1594     size_t length;
  1595     unsigned from = 0;
  1596 
  1597     PEP_STATUS status = PEP_STATUS_OK;
  1598 
  1599     assert(session);
  1600     assert(fprstr);
  1601 
  1602     if (!session || !fprstr)
  1603         return PEP_UNKNOWN_ERROR;
  1604 
  1605     if(pthread_mutex_lock(&netpgp_mutex)){
  1606         return PEP_UNKNOWN_ERROR;
  1607     }
  1608 
  1609     // FIXME : deduplicate that code w/ renew
  1610     if (!str_to_fpr(fprstr, fpr, &length)) {
  1611         status = PEP_ILLEGAL_VALUE;
  1612         goto unlock_netpgp;
  1613     }
  1614 
  1615     pgp_key_t *pkey = pgp_getkeybyfpr(
  1616                            netpgp.io,
  1617                            netpgp.pubring,
  1618                            fpr, length, &from, NULL,
  1619                            1, 0); /* reject revoked, accept expired */
  1620 
  1621     if(pkey == NULL)
  1622     {
  1623         status = PEP_KEY_NOT_FOUND;
  1624         goto unlock_netpgp;
  1625     }
  1626 
  1627     from = 0;
  1628     pgp_key_t *skey = pgp_getkeybyfpr(
  1629                            netpgp.io,
  1630                            netpgp.secring,
  1631                            fpr, length, &from, NULL,
  1632                            1, 0); /* reject revoked, accept expired */
  1633 
  1634     if(skey == NULL)
  1635     {
  1636         status = PEP_KEY_NOT_FOUND;
  1637         goto unlock_netpgp;
  1638     }
  1639 
  1640     pgp_key_revoke(skey, pkey,
  1641                    0, /* no reason code specified */
  1642                    reason);
  1643 
  1644 unlock_netpgp:
  1645     pthread_mutex_unlock(&netpgp_mutex);
  1646 
  1647     return status;
  1648 }
  1649 
  1650 PEP_STATUS pgp_key_expired(
  1651         PEP_SESSION session,
  1652         const char *fprstr,
  1653         const time_t when,
  1654         bool *expired
  1655     )
  1656 {
  1657     PEP_STATUS status = PEP_STATUS_OK;
  1658     PEP_comm_type comm_type;
  1659 
  1660     assert(session);
  1661     assert(fprstr);
  1662     assert(expired);
  1663 
  1664     if (!session || !fprstr || !expired)
  1665         return PEP_UNKNOWN_ERROR;
  1666 
  1667     // TODO : take "when" in account
  1668 
  1669     *expired = false;
  1670 
  1671     status = pgp_get_key_rating(session, fprstr, &comm_type);
  1672 
  1673     if (status != PEP_STATUS_OK)
  1674         return status;
  1675 
  1676     if (comm_type == PEP_ct_key_expired){
  1677         *expired = true;
  1678     }
  1679 
  1680     return PEP_STATUS_OK;
  1681 }
  1682 
  1683 PEP_STATUS pgp_key_revoked(
  1684         PEP_SESSION session,
  1685         const char *fprstr,
  1686         bool *revoked
  1687     )
  1688 {
  1689     PEP_STATUS status = PEP_STATUS_OK;
  1690     PEP_comm_type comm_type;
  1691 
  1692     assert(session);
  1693     assert(fprstr);
  1694     assert(revoked);
  1695 
  1696     *revoked = false;
  1697 
  1698     status = pgp_get_key_rating(session, fprstr, &comm_type);
  1699 
  1700     if (status != PEP_STATUS_OK)
  1701         return status;
  1702 
  1703     if (comm_type == PEP_ct_key_revoked){
  1704         *revoked = true;
  1705     }
  1706 
  1707     return PEP_STATUS_OK;
  1708 }
  1709 
  1710 PEP_STATUS pgp_key_created(
  1711         PEP_SESSION session,
  1712         const char *fprstr,
  1713         time_t *created
  1714     )
  1715 {
  1716     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1717     pgp_key_t *key;
  1718     size_t length;
  1719     unsigned from = 0;
  1720 
  1721     PEP_STATUS status = PEP_STATUS_OK;
  1722 
  1723     assert(session);
  1724     assert(fprstr);
  1725     assert(created);
  1726 
  1727     if (!session || !fprstr || !created)
  1728         return PEP_UNKNOWN_ERROR;
  1729 
  1730     *created = 0;
  1731 
  1732     if(pthread_mutex_lock(&netpgp_mutex)){
  1733         return PEP_UNKNOWN_ERROR;
  1734     }
  1735 
  1736     if (!str_to_fpr(fprstr, fpr, &length)) {
  1737         status = PEP_ILLEGAL_VALUE;
  1738         goto unlock_netpgp;
  1739     }
  1740 
  1741     key = pgp_getkeybyfpr(
  1742            netpgp.io,
  1743            netpgp.pubring,
  1744            fpr, length, &from, NULL,0,0);
  1745 
  1746     if (key)
  1747     {
  1748         *created = (time_t) key->key.pubkey.birthtime;
  1749     }
  1750     else
  1751     {
  1752         status = PEP_KEY_NOT_FOUND;
  1753         goto unlock_netpgp;
  1754     }
  1755 
  1756 
  1757 
  1758 unlock_netpgp:
  1759     pthread_mutex_unlock(&netpgp_mutex);
  1760 
  1761     return status;
  1762 }
  1763 
  1764 
  1765 PEP_STATUS pgp_list_keyinfo(
  1766         PEP_SESSION session, const char* pattern, stringpair_list_t** keyinfo_list)
  1767 {
  1768 
  1769     if (!session || !keyinfo_list)
  1770         return PEP_UNKNOWN_ERROR;
  1771 
  1772     if (pthread_mutex_lock(&netpgp_mutex))
  1773     {
  1774         return PEP_UNKNOWN_ERROR;
  1775     }
  1776 
  1777 // Unused:
  1778 //    pgp_key_t *key;
  1779 
  1780     PEP_STATUS result;
  1781 
  1782     result = find_keys_do(pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  1783 
  1784     if (!keyinfo_list)
  1785         result = PEP_KEY_NOT_FOUND;
  1786 
  1787 unlock_netpgp:
  1788     pthread_mutex_unlock(&netpgp_mutex);
  1789 
  1790     return result;
  1791 }
  1792 
  1793 /* copied from find_keys, but we need to use a callback that filters. */
  1794 PEP_STATUS pgp_find_private_keys(
  1795     PEP_SESSION session, const char *pattern, stringlist_t **keylist)
  1796 {
  1797     stringlist_t *_keylist, *_k;
  1798 
  1799     PEP_STATUS result;
  1800 
  1801     assert(session);
  1802     assert(pattern);
  1803     assert(keylist);
  1804 
  1805     if (!session || !pattern || !keylist )
  1806     {
  1807         return PEP_ILLEGAL_VALUE;
  1808     }
  1809 
  1810     if (pthread_mutex_lock(&netpgp_mutex))
  1811     {
  1812         return PEP_UNKNOWN_ERROR;
  1813     }
  1814 
  1815     *keylist = NULL;
  1816     _keylist = new_stringlist(NULL);
  1817     if (_keylist == NULL) {
  1818         result = PEP_OUT_OF_MEMORY;
  1819         goto unlock_netpgp;
  1820     }
  1821     _k = _keylist;
  1822 
  1823     result = find_keys_do(pattern, &add_secret_key_fpr_to_stringlist, &_k);
  1824 
  1825     if (result == PEP_STATUS_OK) {
  1826         *keylist = _keylist;
  1827         // Transfer ownership, no free
  1828         goto unlock_netpgp;
  1829     }
  1830 
  1831 free_keylist:
  1832     free_stringlist(_keylist);
  1833 
  1834 unlock_netpgp:
  1835     pthread_mutex_unlock(&netpgp_mutex);
  1836 
  1837     return result;
  1838 }
  1839 
  1840 PEP_STATUS pgp_contains_priv_key(
  1841     PEP_SESSION session,
  1842     const char *fpr,
  1843     bool *has_private) {
  1844     stringlist_t* keylist = NULL;
  1845     PEP_STATUS status = pgp_find_private_keys(session, fpr, &keylist);
  1846     if (status == PEP_STATUS_OK && keylist) {
  1847         free_stringlist(keylist);
  1848         *has_private = true;
  1849     }
  1850     else {
  1851         has_private = false;
  1852     }
  1853     return status;
  1854 }