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