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