src/pgp_netpgp.c
author Roker <roker@pep-project.org>
Tue, 20 Sep 2016 15:54:57 +0200
branchroker-linux
changeset 1168 4d4e3ecbaf8b
parent 1054 4c8038969d3c
child 1057 abff13590a4c
child 1126 129b561095a6
permissions -rw-r--r--
merge "default" into my branch
     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_keyinfo_to_stringpair_list(void* arg, pgp_key_t *key) {
  1182     stringpair_list_t** keyinfo_list = (stringpair_list_t**)arg;
  1183     stringpair_t* pair = NULL;
  1184     char* id_fpr = NULL;
  1185     char* primary_userid = (char*)pgp_key_get_primary_userid(key);
  1186 
  1187     bool key_revoked = false;
  1188                 
  1189 //    PEP_STATUS key_status = pgp_key_revoked(session, id_fpr, &key_revoked);
  1190                 
  1191 //    if (key_revoked || key_status == PEP_GET_KEY_FAILED)
  1192 //        return PEP_STATUS_OK; // we just move on
  1193         
  1194     fpr_to_str(&id_fpr, key->pubkeyfpr.fingerprint,
  1195                 key->pubkeyfpr.length);
  1196 
  1197     pair = new_stringpair(id_fpr, primary_userid);
  1198     
  1199     if (pair == NULL)
  1200         return PEP_OUT_OF_MEMORY;
  1201     
  1202     *keyinfo_list = stringpair_list_add(*keyinfo_list, pair);
  1203     free(id_fpr);
  1204     if (*keyinfo_list == NULL)
  1205         return PEP_OUT_OF_MEMORY;
  1206     return PEP_STATUS_OK;
  1207 }
  1208 
  1209 PEP_STATUS pgp_find_keys(
  1210     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1211     )
  1212 {
  1213     stringlist_t *_keylist, *_k;
  1214 
  1215     PEP_STATUS result;
  1216 
  1217     assert(session);
  1218     assert(pattern);
  1219     assert(keylist);
  1220 
  1221     if (!session || !pattern || !keylist )
  1222     {
  1223         return PEP_ILLEGAL_VALUE;
  1224     }
  1225 
  1226     if (pthread_mutex_lock(&netpgp_mutex))
  1227     {
  1228         return PEP_UNKNOWN_ERROR;
  1229     }
  1230 
  1231     *keylist = NULL;
  1232     _keylist = new_stringlist(NULL);
  1233     if (_keylist == NULL) {
  1234         result = PEP_OUT_OF_MEMORY;
  1235         goto unlock_netpgp;
  1236     }
  1237     _k = _keylist;
  1238 
  1239     result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  1240 
  1241     if (result == PEP_STATUS_OK) {
  1242         *keylist = _keylist;
  1243         // Transfer ownership, no free
  1244         goto unlock_netpgp;
  1245     }
  1246 
  1247 free_keylist:
  1248     free_stringlist(_keylist);
  1249 
  1250 unlock_netpgp:
  1251     pthread_mutex_unlock(&netpgp_mutex);
  1252 
  1253     return result;
  1254 }
  1255 
  1256 #define HKP_REQ_PREFIX "keytext="
  1257 #define HKP_REQ_PREFIX_LEN 8
  1258 
  1259 static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
  1260 {
  1261     char *buffer = NULL;
  1262     size_t buflen = 0;
  1263     PEP_STATUS result;
  1264     stringlist_t *encoded_keys;
  1265     encoded_keys = (stringlist_t*)arg;
  1266 
  1267     result = _export_keydata(key, &buffer, &buflen);
  1268     
  1269     if(result == PEP_STATUS_OK){
  1270         char *encoded_key = curl_escape(buffer, (int)buflen);
  1271         if(!encoded_key){
  1272             result = PEP_OUT_OF_MEMORY;
  1273             goto free_buffer;
  1274         }
  1275         size_t encoded_key_len = strlen(encoded_key);
  1276 
  1277         char *request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
  1278         if(!request){
  1279             result = PEP_OUT_OF_MEMORY;
  1280             goto free_encoded_key;
  1281         }
  1282         
  1283         memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
  1284         memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
  1285         request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
  1286 
  1287         if(!stringlist_add(encoded_keys, request)){
  1288             free(request);
  1289             result = PEP_OUT_OF_MEMORY;
  1290         }
  1291 
  1292         free(request);
  1293 
  1294 free_encoded_key:
  1295         curl_free(encoded_key);
  1296 
  1297 free_buffer:        
  1298         free(buffer);
  1299     }
  1300 
  1301     return result;
  1302 }
  1303 
  1304 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1305 {
  1306     static const char *ks_cmd = HKP_SERVER "/pks/add";
  1307 
  1308     PEP_STATUS result;
  1309     CURL *curl = NULL;
  1310 
  1311     assert(session);
  1312     assert(pattern);
  1313 
  1314     if (!session || !pattern )
  1315         return PEP_ILLEGAL_VALUE;
  1316 
  1317     stringlist_t *encoded_keys = new_stringlist(NULL);
  1318     assert(encoded_keys);
  1319     if (encoded_keys == NULL) {
  1320         return PEP_OUT_OF_MEMORY;
  1321     }
  1322 
  1323     if(pthread_mutex_lock(&netpgp_mutex)){
  1324         result = PEP_UNKNOWN_ERROR;
  1325         goto free_encoded_keys;
  1326     }
  1327 
  1328     result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  1329 
  1330     pthread_mutex_unlock(&netpgp_mutex);
  1331 
  1332     if(result != PEP_STATUS_OK){
  1333         goto free_encoded_keys;
  1334     }
  1335 
  1336     if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  1337         result = PEP_UNKNOWN_ERROR;
  1338         goto free_encoded_keys;
  1339     }
  1340 
  1341     result = curl_get_ctx(&curl);
  1342     if(result != PEP_STATUS_OK){
  1343         goto unlock_curl;
  1344     }
  1345 
  1346     if(result == PEP_STATUS_OK){
  1347         CURLcode curlres;
  1348 
  1349         for (const stringlist_t *post = encoded_keys; post != NULL; post = post->next) {
  1350             assert(post->value);
  1351 
  1352             curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
  1353             curl_easy_setopt(curl, CURLOPT_POST, 1L);
  1354             curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
  1355             curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
  1356 
  1357             // Uncomment if debugging
  1358             // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  1359 
  1360             curlres = curl_easy_perform(curl);
  1361 
  1362             if(curlres != CURLE_OK) {
  1363 
  1364                 result = PEP_CANNOT_SEND_KEY;
  1365                 goto release_curl_ctx;
  1366             }
  1367         }
  1368     }
  1369 
  1370 release_curl_ctx:
  1371     curl_release_ctx(&curl);
  1372 unlock_curl:
  1373     pthread_mutex_unlock(&session->ctx.curl_mutex);
  1374 free_encoded_keys:
  1375     free_stringlist(encoded_keys);
  1376 
  1377     return result;
  1378 }
  1379 
  1380 
  1381 PEP_STATUS pgp_get_key_rating(
  1382     PEP_SESSION session,
  1383     const char *fprstr,
  1384     PEP_comm_type *comm_type
  1385     )
  1386 {
  1387     pgp_key_t *key;
  1388     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1389     unsigned from = 0;
  1390     size_t length;
  1391 
  1392 
  1393     PEP_STATUS status = PEP_STATUS_OK;
  1394 
  1395     assert(session);
  1396     assert(fprstr);
  1397     assert(comm_type);
  1398 
  1399     if (!session || !fprstr || !comm_type )
  1400         return PEP_ILLEGAL_VALUE;
  1401 
  1402     *comm_type = PEP_ct_unknown;
  1403 
  1404     if(pthread_mutex_lock(&netpgp_mutex)){
  1405         return PEP_UNKNOWN_ERROR;
  1406     }
  1407 
  1408     if (!str_to_fpr(fprstr, fpr, &length)) {
  1409         status = PEP_ILLEGAL_VALUE;
  1410         goto unlock_netpgp;
  1411     }
  1412         
  1413     key = pgp_getkeybyfpr(
  1414            netpgp.io,
  1415            netpgp.pubring,
  1416            fpr, length, &from, NULL,0,0);
  1417 
  1418     if(key == NULL)
  1419     {
  1420         status = PEP_KEY_NOT_FOUND;
  1421         goto unlock_netpgp;
  1422     }
  1423 
  1424     switch(pgp_key_get_rating(key)){
  1425 	case PGP_VALID:
  1426         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1427         break;
  1428     case PGP_WEAK:
  1429         *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1430         break;
  1431     case PGP_TOOSHORT:
  1432         *comm_type = PEP_ct_key_too_short;
  1433         break;
  1434 	case PGP_INVALID:
  1435         *comm_type = PEP_ct_key_b0rken;
  1436         break;
  1437 	case PGP_EXPIRED:
  1438         *comm_type = PEP_ct_key_expired;
  1439         break;
  1440     case PGP_REVOKED:
  1441         *comm_type = PEP_ct_key_revoked;
  1442         break;
  1443     default:
  1444         break;
  1445     }
  1446 
  1447 unlock_netpgp:
  1448     pthread_mutex_unlock(&netpgp_mutex);
  1449 
  1450     return status;
  1451 }
  1452 
  1453 PEP_STATUS pgp_renew_key(
  1454         PEP_SESSION session,
  1455         const char *fprstr,
  1456         const timestamp *ts
  1457     )
  1458 {
  1459     pgp_key_t *pkey;
  1460     pgp_key_t *skey;
  1461     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1462     size_t length;
  1463     unsigned from = 0;
  1464     time_t duration;
  1465     const uint8_t *primid;
  1466 
  1467     PEP_STATUS status = PEP_STATUS_OK;
  1468 
  1469     assert(session);
  1470     assert(fprstr);
  1471 
  1472     if (!session || !fprstr )
  1473         return PEP_ILLEGAL_VALUE;
  1474 
  1475     if(ts)
  1476     {
  1477         time_t    now, when;
  1478         now = time(NULL);
  1479         when = mktime((struct tm*)ts);
  1480         if(now && when && when > now){
  1481             duration = when - now;
  1482         }else{
  1483             return PEP_ILLEGAL_VALUE;
  1484         }
  1485     }else{
  1486         /* Default 1 year from now */
  1487         duration = 365*24*3600;
  1488     }
  1489 
  1490     if(pthread_mutex_lock(&netpgp_mutex)){
  1491         return PEP_UNKNOWN_ERROR;
  1492     }
  1493 
  1494     
  1495     if (!str_to_fpr(fprstr, fpr, &length)) {
  1496         status = PEP_ILLEGAL_VALUE;
  1497         goto unlock_netpgp;
  1498     }
  1499     
  1500     pkey = pgp_getkeybyfpr(
  1501                           netpgp.io,
  1502                           netpgp.pubring,
  1503                           fpr, length, &from, NULL,
  1504                           1, 0); /* reject revoked, accept expired */
  1505 
  1506     if(pkey == NULL)
  1507     {
  1508         status = PEP_KEY_NOT_FOUND;
  1509         goto unlock_netpgp;
  1510     }
  1511 
  1512     from = 0;
  1513     skey = pgp_getkeybyfpr(
  1514                            netpgp.io,
  1515                            netpgp.secring,
  1516                            fpr, length, &from, NULL,
  1517                            1, 0); /* reject revoked, accept expired */
  1518 
  1519     if(skey == NULL)
  1520     {
  1521         status = PEP_KEY_NOT_FOUND;
  1522         goto unlock_netpgp;
  1523     }
  1524 
  1525     if((primid = pgp_key_get_primary_userid(skey)) == NULL)
  1526     {
  1527         status = PEP_KEY_HAS_AMBIG_NAME;
  1528         goto unlock_netpgp;
  1529     }
  1530 
  1531     // FIXME : renew in a more gentle way
  1532     if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
  1533     {
  1534         status = PEP_CANNOT_CREATE_KEY;
  1535         goto unlock_netpgp;
  1536     }
  1537 
  1538     // save rings
  1539     if (netpgp_save_pubring(&netpgp) &&
  1540         netpgp_save_secring(&netpgp))
  1541     {
  1542         status = PEP_STATUS_OK;
  1543     }else{
  1544         status = PEP_UNKNOWN_ERROR;
  1545     }
  1546     
  1547 unlock_netpgp:
  1548     pthread_mutex_unlock(&netpgp_mutex);
  1549 
  1550     return status;
  1551 }
  1552 
  1553 PEP_STATUS pgp_revoke_key(
  1554         PEP_SESSION session,
  1555         const char *fprstr,
  1556         const char *reason
  1557     )
  1558 {
  1559     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1560     size_t length;
  1561     unsigned from = 0;
  1562 
  1563     PEP_STATUS status = PEP_STATUS_OK;
  1564 
  1565     assert(session);
  1566     assert(fprstr);
  1567 
  1568     if (!session || !fprstr)
  1569         return PEP_UNKNOWN_ERROR;
  1570 
  1571     if(pthread_mutex_lock(&netpgp_mutex)){
  1572         return PEP_UNKNOWN_ERROR;
  1573     }
  1574 
  1575     // FIXME : deduplicate that code w/ renew
  1576     if (!str_to_fpr(fprstr, fpr, &length)) {
  1577         status = PEP_ILLEGAL_VALUE;
  1578         goto unlock_netpgp;
  1579     }
  1580     
  1581     pgp_key_t *pkey = pgp_getkeybyfpr(
  1582                            netpgp.io,
  1583                            netpgp.pubring,
  1584                            fpr, length, &from, NULL,
  1585                            1, 0); /* reject revoked, accept expired */
  1586     
  1587     if(pkey == NULL)
  1588     {
  1589         status = PEP_KEY_NOT_FOUND;
  1590         goto unlock_netpgp;
  1591     }
  1592     
  1593     from = 0;
  1594     pgp_key_t *skey = pgp_getkeybyfpr(
  1595                            netpgp.io,
  1596                            netpgp.secring,
  1597                            fpr, length, &from, NULL,
  1598                            1, 0); /* reject revoked, accept expired */
  1599     
  1600     if(skey == NULL)
  1601     {
  1602         status = PEP_KEY_NOT_FOUND;
  1603         goto unlock_netpgp;
  1604     }
  1605 
  1606     pgp_key_revoke(skey, pkey,
  1607                    0, /* no reason code specified */
  1608                    reason);
  1609 
  1610 unlock_netpgp:
  1611     pthread_mutex_unlock(&netpgp_mutex);
  1612 
  1613     return status;
  1614 }
  1615 
  1616 PEP_STATUS pgp_key_expired(
  1617         PEP_SESSION session,
  1618         const char *fprstr,
  1619         const time_t when,
  1620         bool *expired
  1621     )
  1622 {
  1623     PEP_STATUS status = PEP_STATUS_OK;
  1624     PEP_comm_type comm_type;
  1625 
  1626     assert(session);
  1627     assert(fprstr);
  1628     assert(expired);
  1629 
  1630     if (!session || !fprstr || !expired)
  1631         return PEP_UNKNOWN_ERROR;
  1632 
  1633     // TODO : take "when" in account 
  1634 
  1635     *expired = false;
  1636 
  1637     status = pgp_get_key_rating(session, fprstr, &comm_type);
  1638 
  1639     if (status != PEP_STATUS_OK)
  1640         return status;
  1641 
  1642     if (comm_type == PEP_ct_key_expired){
  1643         *expired = true;
  1644     }
  1645 
  1646     return PEP_STATUS_OK;
  1647 }
  1648 
  1649 PEP_STATUS pgp_key_revoked(
  1650         PEP_SESSION session,
  1651         const char *fprstr,
  1652         bool *revoked
  1653     )
  1654 {
  1655     PEP_STATUS status = PEP_STATUS_OK;
  1656     PEP_comm_type comm_type;
  1657     
  1658     assert(session);
  1659     assert(fprstr);
  1660     assert(revoked);
  1661     
  1662     *revoked = false;
  1663     
  1664     status = pgp_get_key_rating(session, fprstr, &comm_type);
  1665     
  1666     if (status != PEP_STATUS_OK)
  1667         return status;
  1668     
  1669     if (comm_type == PEP_ct_key_revoked){
  1670         *revoked = true;
  1671     }
  1672     
  1673     return PEP_STATUS_OK;
  1674 }
  1675 
  1676 
  1677 PEP_STATUS pgp_list_keyinfo(
  1678         PEP_SESSION session, const char* pattern, stringpair_list_t** keyinfo_list)
  1679 {
  1680     
  1681     if (!session || !keyinfo_list)
  1682         return PEP_UNKNOWN_ERROR;
  1683     
  1684     if (pthread_mutex_lock(&netpgp_mutex))
  1685     {
  1686         return PEP_UNKNOWN_ERROR;
  1687     }
  1688     
  1689     pgp_key_t *key;
  1690 
  1691     PEP_STATUS result;
  1692     
  1693     result = find_keys_do(pattern, &add_keyinfo_to_stringpair_list, (void*)keyinfo_list);
  1694     
  1695     if (!keyinfo_list)
  1696         result = PEP_KEY_NOT_FOUND;
  1697     
  1698 unlock_netpgp:
  1699     pthread_mutex_unlock(&netpgp_mutex);
  1700     
  1701     return result;
  1702 }
  1703 
  1704