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