src/pgp_netpgp.c
author Edouard Tisserant
Sun, 17 May 2015 00:58:43 +0200
changeset 279 99e9815751fa
parent 277 5c8838004648
child 286 bac6a8feb1cf
permissions -rw-r--r--
netpgp : check key consistency and validity (direct signature) at import
     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 unlock_netpgp:
    67     pthread_mutex_unlock(&netpgp_mutex);
    68     
    69     return status;
    70 }
    71 
    72 static void release_netpgp()
    73 {
    74     if(pthread_mutex_lock(&netpgp_mutex)){
    75         return;
    76     }
    77     netpgp_end(&netpgp);
    78     memset(&netpgp, 0x0, sizeof(netpgp_t));
    79 
    80     pthread_mutex_destroy(&netpgp_mutex);
    81 
    82     return;
    83 }
    84 
    85 static PEP_STATUS init_curl(
    86     CURL **curl,
    87     pthread_mutex_t *curl_mutex,
    88     bool in_first)
    89 {
    90     PEP_STATUS status = PEP_STATUS_OK;
    91     struct curl_slist *headers=NULL;
    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     if ((*curl = curl_easy_init()) == NULL) {
   106         return PEP_OUT_OF_MEMORY;
   107     }
   108 
   109     curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
   110     curl_easy_setopt(*curl, CURLOPT_MAXREDIRS, 3L);
   111 
   112     headers=curl_slist_append(headers,"Pragma: no-cache");
   113     if(headers)
   114         headers=curl_slist_append(headers,"Cache-Control: no-cache");
   115 
   116     if(!headers)
   117     {
   118         status = PEP_OUT_OF_MEMORY;
   119         goto unlock_curl;
   120     }
   121 
   122     curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
   123     curl_slist_free_all(headers);
   124 
   125     // TODO curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
   126 
   127 unlock_curl:
   128     pthread_mutex_unlock(curl_mutex);
   129     return status;
   130 }
   131 
   132 static void release_curl(
   133     CURL **curl,
   134     pthread_mutex_t *curl_mutex, 
   135     bool out_last)
   136 {
   137     if(pthread_mutex_lock(curl_mutex)){
   138         return;
   139     }
   140 
   141     if(*curl)
   142         curl_easy_cleanup(*curl);
   143 
   144     *curl = NULL;
   145 
   146     if(out_last){
   147         curl_global_cleanup();
   148     }
   149 
   150     pthread_mutex_destroy(curl_mutex);
   151 
   152     return;
   153 }
   154 
   155 PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   156 {
   157     PEP_STATUS status = PEP_STATUS_OK;
   158 
   159     assert(session);
   160     if(!session) return PEP_UNKNOWN_ERROR;
   161 
   162     if (in_first) {
   163         if((status = init_netpgp()) != PEP_STATUS_OK)
   164         return status;
   165     }
   166 
   167     if((status = init_curl(
   168                     &session->ctx.curl,
   169                     &session->ctx.curl_mutex,
   170                     in_first) != PEP_STATUS_OK)){
   171         if(in_first) release_netpgp();
   172         return status;
   173     }
   174 
   175     return PEP_STATUS_OK;
   176 }
   177 
   178 void pgp_release(PEP_SESSION session, bool out_last)
   179 {
   180     assert(session);
   181     if(!session) return;
   182 
   183     if (out_last){
   184         release_netpgp();
   185     }
   186     release_curl(&session->ctx.curl, &session->ctx.curl_mutex, out_last);
   187 }
   188 
   189 // return 1 if the file contains ascii-armoured text 
   190 // buf MUST be \0 terminated to be checked for armour
   191 static unsigned
   192 _armoured(const char *buf, size_t size, const char *pattern)
   193 {
   194     unsigned armoured = 0;
   195     if(buf[size]=='\0'){
   196         regex_t r;
   197         regcomp(&r, pattern, REG_EXTENDED|REG_NEWLINE|REG_NOSUB);
   198         if (regexec(&r, buf, 0, NULL, 0) == 0) {
   199             armoured = 1;
   200         }
   201         regfree(&r);
   202     }
   203     return armoured;
   204 }
   205 
   206 /* return key ID's hexdump as a string */
   207 static void id_to_str(const uint8_t *userid, char *fpr)
   208 {
   209     int i;
   210     static const char *hexes = "0123456789abcdef";
   211     for (i = 0; i < 8 ; i++) {
   212         fpr[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
   213         fpr[(i * 2) + 1] = hexes[userid[i] & 0xf];
   214     }
   215     fpr[8 * 2] = 0x0;
   216 }
   217 
   218 // Iterate through netpgp' reported valid signatures 
   219 // fill a list of valid figerprints
   220 // returns PEP_STATUS_OK if all sig reported valid
   221 // error status otherwise.
   222 static PEP_STATUS _validation_results(
   223         netpgp_t *netpgp,
   224         pgp_validation_t *vresult,
   225         stringlist_t **_keylist
   226     )
   227 {
   228     time_t    now;
   229     time_t    t;
   230     char    buf[128];
   231 
   232     now = time(NULL);
   233     if (now < vresult->birthtime) {
   234         // signature is not valid yet
   235         return PEP_UNENCRYPTED;
   236     }
   237     if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
   238         // signature has expired
   239         t = vresult->duration + vresult->birthtime;
   240         return PEP_UNENCRYPTED;
   241     }
   242     if (vresult->validc && vresult->valid_sigs &&
   243         !vresult->invalidc && !vresult->unknownc ) {
   244         unsigned    n;
   245         stringlist_t *k;
   246         // caller responsible to free
   247         *_keylist = new_stringlist(NULL);
   248         assert(*_keylist);
   249         if (*_keylist == NULL) {
   250             return PEP_OUT_OF_MEMORY;
   251         }
   252         k = *_keylist;
   253         for (n = 0; n < vresult->validc; ++n) {
   254             char id[MAX_ID_LENGTH + 1];
   255             const uint8_t *userid = vresult->valid_sigs[n].signer_id;
   256 
   257             id_to_str(userid, id);
   258 
   259             k = stringlist_add(k, id);
   260             if(!k){
   261                 free_stringlist(*_keylist);
   262                 return PEP_OUT_OF_MEMORY;
   263             }
   264         }
   265         return PEP_STATUS_OK;
   266     }
   267     if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
   268         // No signatures found - is this memory signed?
   269         return PEP_VERIFY_NO_KEY; 
   270     } 
   271     
   272     if (vresult->invalidc) {
   273         // some invalid signatures
   274         return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   275     }
   276     
   277     // only unknown sigs
   278     return PEP_DECRYPT_WRONG_FORMAT;
   279 }
   280 
   281 #define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----\\s*$"
   282 PEP_STATUS pgp_decrypt_and_verify(
   283     PEP_SESSION session, const char *ctext, size_t csize,
   284     char **ptext, size_t *psize, stringlist_t **keylist
   285     )
   286 {
   287     pgp_memory_t *mem;
   288     pgp_memory_t *cat;
   289     pgp_validation_t *vresult;
   290     char *_ptext = NULL;
   291     size_t _psize = 0;
   292     int ret;
   293 
   294     PEP_STATUS result;
   295     stringlist_t *_keylist = NULL;
   296     int i_key = 0;
   297 
   298     assert(session);
   299     assert(ctext);
   300     assert(csize);
   301     assert(ptext);
   302     assert(psize);
   303     assert(keylist);
   304 
   305     if(!session || !ctext || !csize || !ptext || !psize || !keylist) 
   306         return PEP_UNKNOWN_ERROR;
   307 
   308     if(pthread_mutex_lock(&netpgp_mutex)){
   309         return PEP_UNKNOWN_ERROR;
   310     }
   311 
   312     *ptext = NULL;
   313     *psize = 0;
   314     *keylist = NULL;
   315 
   316     vresult = malloc(sizeof(pgp_validation_t));
   317     memset(vresult, 0x0, sizeof(pgp_validation_t));
   318 
   319     mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
   320                 netpgp.secring, netpgp.pubring,
   321                 _armoured(ctext, csize, ARMOR_HEAD),
   322                 0 /* sshkeys */,
   323                 NULL, -1, NULL  /* pass fp,attempts,cb */);
   324     if (mem == NULL) {
   325         result = PEP_OUT_OF_MEMORY;
   326         goto unlock_netpgp;
   327     }
   328 
   329     _psize = pgp_mem_len(mem);
   330     if (_psize){
   331         if ((_ptext = malloc(_psize + 1)) == NULL) {
   332             result = PEP_OUT_OF_MEMORY;
   333             goto free_pgp;
   334         }
   335         memcpy(_ptext, pgp_mem_data(mem), _psize);
   336         _ptext[_psize] = '\0'; // safeguard for naive users
   337         result = PEP_DECRYPTED;
   338     }else{
   339         result = PEP_DECRYPT_NO_KEY;
   340         goto free_pgp;
   341     }
   342 
   343     if (result == PEP_DECRYPTED) {
   344         result = _validation_results(&netpgp, vresult, &_keylist);
   345         if (result != PEP_STATUS_OK) {
   346             goto free_ptext;
   347         }
   348         result = PEP_DECRYPTED_AND_VERIFIED;
   349     }
   350 
   351     if (result == PEP_DECRYPTED_AND_VERIFIED
   352         || result == PEP_DECRYPTED) {
   353         *ptext = _ptext;
   354         *psize = _psize;
   355         (*ptext)[*psize] = 0; // safeguard for naive users
   356         if (result == PEP_DECRYPTED_AND_VERIFIED) {
   357             *keylist = _keylist;
   358         }
   359 
   360         /* _ptext and _keylist ownership transfer, don't free */
   361         goto free_pgp;
   362     }
   363 
   364 free_keylist:
   365     free_stringlist(_keylist);
   366 
   367 free_ptext:
   368     free(_ptext);
   369 
   370 free_pgp:
   371     pgp_memory_free(mem);
   372     pgp_validate_result_free(vresult);
   373 
   374 unlock_netpgp:
   375     pthread_mutex_unlock(&netpgp_mutex);
   376 
   377     return result;
   378 }
   379 
   380 #define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----\\s*$"
   381 PEP_STATUS pgp_verify_text(
   382     PEP_SESSION session, const char *text, size_t size,
   383     const char *signature, size_t sig_size, stringlist_t **keylist
   384     )
   385 {
   386     pgp_memory_t *signedmem;
   387     pgp_memory_t *sig;
   388     pgp_validation_t *vresult;
   389 
   390     PEP_STATUS result;
   391     stringlist_t *_keylist;
   392 
   393     assert(session);
   394     assert(text);
   395     assert(size);
   396     assert(signature);
   397     assert(sig_size);
   398     assert(keylist);
   399 
   400     if(!session || !text || !size || !signature || !sig_size || !keylist) 
   401         return PEP_UNKNOWN_ERROR;
   402 
   403     if(pthread_mutex_lock(&netpgp_mutex)){
   404         return PEP_UNKNOWN_ERROR;
   405     }
   406 
   407     *keylist = NULL;
   408 
   409     vresult = malloc(sizeof(pgp_validation_t));
   410     if (vresult == NULL) {
   411         result = PEP_OUT_OF_MEMORY;
   412         goto unlock_netpgp;
   413     }
   414     memset(vresult, 0x0, sizeof(pgp_validation_t));
   415 
   416     signedmem = pgp_memory_new();
   417     if (signedmem == NULL) {
   418         result = PEP_OUT_OF_MEMORY;
   419         goto unlock_netpgp;
   420     }
   421     pgp_memory_add(signedmem, (const uint8_t*)text, size);
   422 
   423     sig = pgp_memory_new();
   424     if (sig == NULL) {
   425         pgp_memory_free(signedmem);
   426         result = PEP_OUT_OF_MEMORY;
   427         goto unlock_netpgp;
   428     }
   429     pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
   430 
   431     pgp_validate_mem_detached(netpgp.io, vresult, sig,
   432                 NULL,/* output */
   433                 _armoured(signature, sig_size, ARMOR_SIG_HEAD),
   434                 netpgp.pubring,
   435                 signedmem);
   436 
   437     result = _validation_results(&netpgp, vresult, &_keylist);
   438     if (result != PEP_STATUS_OK) {
   439         goto free_pgp;
   440     }else{
   441         result = PEP_VERIFIED;
   442     }
   443 
   444     if (result == PEP_VERIFIED) {
   445         /* TODO : check trust level */
   446         result = PEP_VERIFIED_AND_TRUSTED;
   447     }
   448 
   449     if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
   450         *keylist = _keylist;
   451 
   452         /* _keylist ownership transfer, don't free */
   453         goto free_pgp;
   454     }
   455 
   456 free_keylist:
   457     free_stringlist(_keylist);
   458 
   459 free_pgp:
   460     // free done by pgp_validate_mem_detached
   461     // pgp_memory_free(sig);
   462     // pgp_memory_free(signedmem);
   463     pgp_validate_result_free(vresult);
   464 
   465 unlock_netpgp:
   466     pthread_mutex_unlock(&netpgp_mutex);
   467 
   468     return result;
   469 }
   470 
   471 PEP_STATUS pgp_encrypt_and_sign(
   472     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   473     size_t psize, char **ctext, size_t *csize
   474     )
   475 {
   476     const pgp_key_t *keypair;
   477     pgp_seckey_t *seckey;
   478     pgp_memory_t *signedmem;
   479     pgp_memory_t *cmem;
   480     const char *userid;
   481     const char *hashalg;
   482     pgp_keyring_t *rcpts;
   483 
   484     PEP_STATUS result;
   485     const stringlist_t *_keylist;
   486 
   487     assert(session);
   488     assert(keylist);
   489     assert(ptext);
   490     assert(psize);
   491     assert(ctext);
   492     assert(csize);
   493 
   494     if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
   495         return PEP_UNKNOWN_ERROR;
   496 
   497     if(pthread_mutex_lock(&netpgp_mutex)){
   498         return PEP_UNKNOWN_ERROR;
   499     }
   500 
   501     *ctext = NULL;
   502     *csize = 0;
   503 
   504     // Get signing details from netpgp
   505     if ((userid = netpgp_getvar(&netpgp, "userid")) == NULL || 
   506         (keypair = pgp_getkeybyname(netpgp.io, 
   507                                     netpgp.secring, 
   508                                     userid)) == NULL ||
   509         (seckey = pgp_decrypt_seckey(keypair, NULL /*passfp*/)) == NULL) {
   510         return PEP_UNKNOWN_ERROR;
   511     }
   512 
   513     hashalg = netpgp_getvar(&netpgp, "hash");
   514     // netpgp (l)imitation - XXX why ? 
   515     if (seckey->pubkey.alg == PGP_PKA_DSA) {
   516         hashalg = "sha1";
   517     }
   518 
   519     // Sign data
   520     signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
   521                 time(NULL), /* birthtime */
   522                 0 /* duration */,
   523                 hashalg, 
   524                 0 /* armored */,
   525                 0 /* cleartext */);
   526 
   527     pgp_forget(seckey, (unsigned)sizeof(*seckey));
   528 
   529     if (!signedmem) {
   530         result = PEP_UNENCRYPTED;
   531         goto unlock_netpgp;
   532     }
   533 
   534     // Encrypt signed data
   535     if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
   536         result = PEP_OUT_OF_MEMORY;
   537         goto free_signedmem;
   538     }
   539     for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
   540         assert(_keylist->value);
   541         // get key from netpgp's pubring
   542         const pgp_key_t *key;
   543         key = pgp_getkeybyname(netpgp.io,
   544                                netpgp.pubring,
   545                                _keylist->value);
   546 
   547         if(key == NULL){
   548             result = PEP_KEY_NOT_FOUND;
   549             goto free_rcpts;
   550         }
   551 
   552         // add key to recipients/signers
   553         pgp_keyring_add(rcpts, key);
   554         if(rcpts->keys == NULL){
   555             result = PEP_OUT_OF_MEMORY;
   556             goto free_signedmem;
   557         }
   558     }
   559 
   560     cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
   561             pgp_mem_len(signedmem), rcpts, 1 /* armored */,
   562             netpgp_getvar(&netpgp, "cipher"), 
   563             1 /* takes raw OpenPGP message */);
   564 
   565     if (cmem == NULL) {
   566         result = PEP_OUT_OF_MEMORY;
   567         goto free_signedmem;
   568     }else{
   569 
   570         char *_buffer = NULL;
   571         size_t length = pgp_mem_len(cmem);
   572 
   573         // Allocate transferable buffer
   574         _buffer = malloc(length + 1);
   575         assert(_buffer);
   576         if (_buffer == NULL) {
   577             result = PEP_OUT_OF_MEMORY;
   578             goto free_cmem;
   579         }
   580 
   581         memcpy(_buffer, pgp_mem_data(cmem), length);
   582 
   583         *ctext = _buffer;
   584         *csize = length;
   585         (*ctext)[*csize] = 0; // safeguard for naive users
   586         result = PEP_STATUS_OK;
   587     }
   588 
   589 free_cmem :
   590     pgp_memory_free(cmem);
   591 free_rcpts :
   592     pgp_keyring_free(rcpts);
   593 free_signedmem :
   594     pgp_memory_free(signedmem);
   595 unlock_netpgp:
   596     pthread_mutex_unlock(&netpgp_mutex);
   597 
   598     return result;
   599 }
   600 
   601 /* return the hexdump as a string */
   602 static unsigned
   603 fpr_to_str (char **str, const uint8_t *fpr, size_t length)
   604 {
   605     unsigned i;
   606     int	n;
   607 
   608     /* 5 char per byte (hexes + space) tuple -1 space at the end + null */
   609     *str = malloc((length / 2) * 5 - 1 + 1);
   610 
   611     if(*str == NULL)
   612         return 0;
   613 
   614     for (n = 0, i = 0 ; i < length - 2; i += 2) {
   615     	n += snprintf(&((*str)[n]), 6, "%02x%02x ", fpr[i], fpr[i+1]);
   616     }
   617     snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
   618 
   619     return 1;
   620 }
   621 
   622 static unsigned
   623 str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
   624 {
   625     unsigned i,j;
   626 
   627     *length = 0;
   628 
   629     while(*str && *length < PGP_FINGERPRINT_SIZE){
   630         while (*str == ' ') str++;
   631         for (j = 0; j < 2; j++) {
   632             uint8_t *byte = &fpr[*length];
   633             *byte = 0;
   634             for (i = 0; i < 2; i++) {
   635                 if (i > 0)
   636                     *byte = *byte << 4;
   637                 if (*str >= 'a' && *str <= 'f')
   638                     *byte += 10 + *str - 'a';
   639                 else if (*str >= 'A' && *str <= 'F')
   640                     *byte += 10 + *str - 'A';
   641                 else if (*str >= '0' && *str <= '9')
   642                     *byte += *str - '0';
   643                 else 
   644                     return 0;
   645                 str++;
   646             }
   647             (*length)++;
   648         }
   649     }
   650     return 1;
   651 }
   652 
   653 static PEP_STATUS import_key_or_keypair(netpgp_t *netpgp, pgp_key_t *newkey){
   654     pgp_key_t pubkey;
   655     unsigned public;
   656     PEP_STATUS result;
   657     pgp_keyring_t tmpring;
   658 	pgp_validation_t *vresult;
   659 
   660     /* XXX TODO : replace/update key if already in ring */
   661 
   662     if ((public = (newkey->type == PGP_PTAG_CT_PUBLIC_KEY))){
   663         pubkey = *newkey;
   664     } else {
   665         // Duplicate key as public only
   666         bzero(&pubkey, sizeof(pubkey));
   667         if (!pgp_keydata_dup(&pubkey, newkey, 1 /* make_public */)){
   668             return PEP_OUT_OF_MEMORY;
   669         }
   670     }
   671 
   672     // Verify pubkey against a temporary keyring containing the key itself
   673     // (netpgp does check subkey binding sigs agains all the given ring,
   674     // and doesn't ensure signer is the primary key itself)
   675     bzero(&tmpring, sizeof(tmpring));
   676     if(!pgp_keyring_add(&tmpring, &pubkey)){
   677         result = PEP_OUT_OF_MEMORY;
   678         goto free_pubkey;
   679     }
   680 
   681     vresult = malloc(sizeof(pgp_validation_t));
   682     memset(vresult, 0x0, sizeof(pgp_validation_t));
   683     pgp_validate_key_sigs(vresult, &pubkey, &tmpring, NULL);
   684     pgp_keyring_free(&tmpring);
   685     
   686     // There may be no single valid signature (not mandatory)
   687     // but at least there must be no invalid signature
   688     if (vresult->invalidc) {
   689         result = PEP_UNKNOWN_ERROR;
   690     } else {
   691 
   692         // check key consistency by ensuring no subkey or 
   693         // direct signature are unknown
   694         unsigned    n;
   695         result = PEP_STATUS_OK;
   696         for (n = 0; n < vresult->unknownc && result == PEP_STATUS_OK; ++n) {
   697             switch (vresult->unknown_sigs[n].type) {
   698             case PGP_SIG_SUBKEY:
   699             case PGP_SIG_DIRECT:
   700 	        case PGP_SIG_PRIMARY: /* TODO is ignored by netpgp XXX */
   701                 result = PEP_UNKNOWN_ERROR;
   702                 break;
   703             default:
   704                 break;
   705             }
   706         }
   707         // TODO check in netpgp parser source that 
   708         // presence of a subkey binding signature
   709         // is enforced
   710     }
   711 
   712     pgp_validate_result_free(vresult);
   713 
   714     if (result != PEP_STATUS_OK) {
   715         if (!public) goto free_pubkey;
   716         return result;
   717     }
   718     // Append key to netpgp's rings (key ownership transfered)
   719     if (!public && !pgp_keyring_add(netpgp->secring, newkey)){
   720         result = PEP_OUT_OF_MEMORY;
   721         goto free_pubkey;
   722     } else if (!pgp_keyring_add(netpgp->pubring, &pubkey)){
   723         result = PEP_OUT_OF_MEMORY;
   724         goto pop_secring;
   725     }
   726 
   727     // save rings 
   728     if (netpgp_save_pubring(netpgp) && 
   729         (!public || netpgp_save_secring(netpgp)))
   730     {
   731         /* free nothing, everything transfered */
   732         return PEP_STATUS_OK;
   733     } else {
   734         /* XXX in case only pubring save succeed
   735          * pubring file is left as-is, but backup restore
   736          * could be attempted if such corner case matters */
   737         result = PEP_UNKNOWN_ERROR;
   738     }
   739 
   740 pop_pubring:
   741     ((pgp_keyring_t *)netpgp->pubring)->keyc--;
   742 pop_secring:
   743     ((pgp_keyring_t *)netpgp->secring)->keyc--;
   744 free_pubkey:
   745     pgp_key_free(&pubkey);
   746 
   747     return result;
   748 }
   749 
   750 PEP_STATUS pgp_generate_keypair(
   751     PEP_SESSION session, pEp_identity *identity
   752     )
   753 {
   754     pgp_key_t	newkey;
   755 
   756     PEP_STATUS result;
   757     char newid[1024];
   758     const char *hashalg;
   759     const char *cipher;
   760 
   761     assert(session);
   762     assert(identity);
   763     assert(identity->address);
   764     assert(identity->fpr == NULL);
   765     assert(identity->username);
   766 
   767     if(!session || !identity || 
   768        !identity->address || identity->fpr || !identity->username)
   769         return PEP_UNKNOWN_ERROR;
   770 
   771     if(pthread_mutex_lock(&netpgp_mutex)){
   772         return PEP_UNKNOWN_ERROR;
   773     }
   774 
   775     if(snprintf(newid, sizeof(newid),
   776         "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
   777         result =  PEP_BUFFER_TOO_SMALL;
   778         goto unlock_netpgp;
   779     }
   780     
   781     hashalg = netpgp_getvar(&netpgp, "hash");
   782     cipher = netpgp_getvar(&netpgp, "cipher");
   783 
   784     bzero(&newkey, sizeof(newkey));
   785 
   786     // Generate the key
   787     if (!pgp_rsa_generate_keypair(&newkey, 4096, 65537UL, hashalg, cipher,
   788                                   (const uint8_t *) "", (const size_t) 0) ||
   789         !pgp_add_selfsigned_userid(&newkey, (uint8_t *)newid)) {
   790         result = PEP_CANNOT_CREATE_KEY;
   791         goto free_newkey;
   792     }
   793 
   794     // TODO "Expire-Date: 1y\n";
   795 
   796 
   797     result = import_key_or_keypair(&netpgp, &newkey);
   798 
   799     if (result == PEP_STATUS_OK) {
   800         char *fprstr = NULL;
   801         fpr_to_str(&fprstr,
   802                    newkey.sigfingerprint.fingerprint,
   803                    newkey.sigfingerprint.length);
   804         if (fprstr == NULL) {
   805             result = PEP_OUT_OF_MEMORY;
   806             goto free_newkey;
   807         } 
   808         identity->fpr = fprstr;
   809         /* free nothing, everything transfered */
   810         result = PEP_STATUS_OK;
   811         goto unlock_netpgp;
   812     }
   813 
   814 free_newkey:
   815     pgp_key_free(&newkey);
   816 unlock_netpgp:
   817     pthread_mutex_unlock(&netpgp_mutex);
   818 
   819     return result;
   820 }
   821 
   822 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
   823 {
   824     uint8_t fpr[PGP_FINGERPRINT_SIZE];
   825     size_t length;
   826 
   827     PEP_STATUS result;
   828 
   829     assert(session);
   830     assert(fpr);
   831 
   832     if (!session || !fpr)
   833         return PEP_UNKNOWN_ERROR;
   834 
   835     if(pthread_mutex_lock(&netpgp_mutex)){
   836         return PEP_UNKNOWN_ERROR;
   837     }
   838     
   839     if (str_to_fpr(fprstr, fpr, &length)) {
   840         unsigned insec = pgp_deletekeybyfpr(netpgp.io,
   841                                 (pgp_keyring_t *)netpgp.secring, 
   842                                 (const uint8_t *)fpr, length);
   843         unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
   844                                 (pgp_keyring_t *)netpgp.pubring, 
   845                                 (const uint8_t *)fpr, length);
   846         if(!insec && !inpub){
   847             result = PEP_KEY_NOT_FOUND;
   848             goto unlock_netpgp;
   849         } else {
   850             result = PEP_STATUS_OK;
   851         }
   852     }else{
   853         result = PEP_OUT_OF_MEMORY;
   854         goto unlock_netpgp;
   855     }
   856 
   857     // save rings (key ownership transfered)
   858     if (netpgp_save_pubring(&netpgp) && 
   859         netpgp_save_secring(&netpgp))
   860     {
   861         result = PEP_STATUS_OK;
   862     }else{
   863         result = PEP_UNKNOWN_ERROR;
   864     }
   865 
   866 unlock_netpgp:
   867     pthread_mutex_unlock(&netpgp_mutex);
   868 
   869     return result;
   870 }
   871 
   872 #define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----\\s*$"
   873 PEP_STATUS pgp_import_keydata(
   874         PEP_SESSION session,
   875         const char *key_data, 
   876         size_t size
   877     )
   878 {
   879     pgp_memory_t *mem;
   880     pgp_keyring_t tmpring;
   881     unsigned i = 0;
   882 
   883     PEP_STATUS result = PEP_STATUS_OK;
   884 
   885     assert(session);
   886     assert(key_data);
   887 
   888     if(!session || !key_data) 
   889         return PEP_UNKNOWN_ERROR;
   890 
   891     if(pthread_mutex_lock(&netpgp_mutex)){
   892         return PEP_UNKNOWN_ERROR;
   893     }
   894 
   895     mem = pgp_memory_new();
   896     if (mem == NULL) {
   897         result = PEP_OUT_OF_MEMORY;
   898         goto unlock_netpgp;
   899     }
   900     pgp_memory_add(mem, (const uint8_t*)key_data, size);
   901 
   902     bzero(&tmpring, sizeof(tmpring));
   903 
   904     if (pgp_keyring_read_from_mem(netpgp.io, &tmpring, 
   905                                   _armoured(key_data, size, ARMOR_KEY_HEAD),
   906                                   mem) == 0){
   907         result = PEP_ILLEGAL_VALUE;
   908     }else if (tmpring.keyc == 0){
   909         result = PEP_UNKNOWN_ERROR;
   910     }else while(result == PEP_STATUS_OK && i < tmpring.keyc){
   911         result = import_key_or_keypair(&netpgp, &tmpring.keys[i++]);
   912     }
   913     
   914     pgp_memory_free(mem);
   915 
   916     if (result == PEP_STATUS_OK){
   917         pgp_keyring_free(&tmpring);
   918     }else{
   919         pgp_keyring_purge(&tmpring);
   920     }
   921 
   922 unlock_netpgp:
   923     pthread_mutex_unlock(&netpgp_mutex);
   924 
   925     return result;
   926 }
   927 
   928 PEP_STATUS pgp_export_keydata(
   929     PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
   930     )
   931 {
   932     pgp_key_t *key;
   933 	pgp_output_t *output;
   934     pgp_memory_t *mem;
   935     uint8_t fpr[PGP_FINGERPRINT_SIZE];
   936     size_t fprlen;
   937 
   938     PEP_STATUS result;
   939     char *buffer;
   940     size_t buflen;
   941 
   942     assert(session);
   943     assert(fprstr);
   944     assert(key_data);
   945     assert(size);
   946 
   947     if (!session || !fprstr || !key_data || !size)
   948         return PEP_UNKNOWN_ERROR;
   949 
   950     if(pthread_mutex_lock(&netpgp_mutex)){
   951         return PEP_UNKNOWN_ERROR;
   952     }
   953 
   954     if (str_to_fpr(fprstr, fpr, &fprlen)) {
   955         if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring, 
   956                                                 fpr, fprlen,
   957                                                 NULL)) == NULL) {
   958             result = PEP_KEY_NOT_FOUND;
   959             goto unlock_netpgp;
   960         }
   961     }else{
   962         result = PEP_OUT_OF_MEMORY;
   963         goto unlock_netpgp;
   964     }
   965     
   966 	pgp_setup_memory_write(&output, &mem, 128);
   967 
   968     if (mem == NULL || output == NULL) {
   969         result = PEP_OUT_OF_MEMORY;
   970         goto unlock_netpgp;
   971     }
   972 
   973     if (!pgp_write_xfer_pubkey(output, key, 1)) {
   974         result = PEP_UNKNOWN_ERROR;
   975         goto free_mem;
   976     }
   977 
   978     buffer = NULL;
   979     buflen = pgp_mem_len(mem);
   980 
   981     // Allocate transferable buffer
   982     buffer = malloc(buflen + 1);
   983     assert(buffer);
   984     if (buffer == NULL) {
   985         result = PEP_OUT_OF_MEMORY;
   986         goto free_mem;
   987     }
   988 
   989     memcpy(buffer, pgp_mem_data(mem), buflen);
   990 
   991     *key_data = buffer;
   992     *size = buflen;
   993     (*key_data)[*size] = 0; // safeguard for naive users
   994     result = PEP_STATUS_OK;
   995 
   996 free_mem :
   997 	pgp_teardown_memory_write(output, mem);
   998 unlock_netpgp:
   999     pthread_mutex_unlock(&netpgp_mutex);
  1000 
  1001     return result;
  1002 }
  1003 
  1004 struct HKP_answer {
  1005   char *memory;
  1006   size_t size;
  1007 };
  1008  
  1009 static size_t
  1010 HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
  1011 {
  1012   size_t realsize = size * nmemb;
  1013   struct HKP_answer *mem = (struct HKP_answer *)userp;
  1014  
  1015   mem->memory = realloc(mem->memory, mem->size + realsize + 1);
  1016   if(mem->memory == NULL) {
  1017     mem->size = 0;
  1018     return 0;
  1019   }
  1020  
  1021   memcpy(&(mem->memory[mem->size]), contents, realsize);
  1022   mem->size += realsize;
  1023   mem->memory[mem->size] = 0;
  1024  
  1025   return realsize;
  1026 }
  1027 
  1028 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1029 {
  1030     static const char *ks_cmd = "http://keys.gnupg.net:11371/pks/lookup?"
  1031                                 "op=get&options=mr&exact=on&"
  1032                                 "search=";
  1033     char *encoded_pattern;
  1034     char *request = NULL;
  1035     struct HKP_answer answer;
  1036     CURLcode curlres;
  1037        
  1038     PEP_STATUS result;
  1039 
  1040     CURL *curl;
  1041 
  1042     assert(session);
  1043     assert(pattern);
  1044 
  1045     if (!session || !pattern )
  1046         return PEP_UNKNOWN_ERROR;
  1047 
  1048     if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  1049         return PEP_UNKNOWN_ERROR;
  1050     }
  1051 
  1052     curl = session->ctx.curl;
  1053 
  1054     encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
  1055     if(!encoded_pattern){
  1056         result = PEP_OUT_OF_MEMORY;
  1057         goto unlock_curl;
  1058     }
  1059 
  1060     if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
  1061         result = PEP_OUT_OF_MEMORY;
  1062         goto free_encoded_pattern;
  1063     }
  1064 
  1065     //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
  1066     stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
  1067 
  1068     curl_easy_setopt(curl, CURLOPT_URL,request);
  1069 
  1070     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
  1071 
  1072     answer.memory = NULL;
  1073     answer.size = 0;
  1074     curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
  1075 
  1076     curlres = curl_easy_perform(curl);
  1077     if(curlres != CURLE_OK) {
  1078         result = PEP_GET_KEY_FAILED;
  1079         goto free_request;
  1080     }
  1081 
  1082     if(!answer.memory || !answer.size) {
  1083         result = PEP_OUT_OF_MEMORY;
  1084         goto free_request;
  1085     }
  1086 
  1087     result = pgp_import_keydata(session, 
  1088                                 answer.memory, 
  1089                                 answer.size);
  1090 
  1091 free_answer:
  1092     free(answer.memory);
  1093 free_request:
  1094     free(request);
  1095 free_encoded_pattern:
  1096     curl_free(encoded_pattern);
  1097 unlock_curl:
  1098     pthread_mutex_unlock(&session->ctx.curl_mutex);
  1099 
  1100     return result;
  1101 }
  1102 
  1103 typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  1104 
  1105 static PEP_STATUS find_keys_do(
  1106         const char *pattern, find_key_cb_t cb, void* cb_arg)
  1107 {
  1108     uint8_t fpr[PGP_FINGERPRINT_SIZE];
  1109     size_t length;
  1110     pgp_key_t *key;
  1111 
  1112     PEP_STATUS result;
  1113 
  1114     // Try find a fingerprint in pattern
  1115     if (str_to_fpr(pattern, fpr, &length)) {
  1116 
  1117         // Only one fingerprint can match
  1118         if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  1119                         netpgp.io,
  1120                         (pgp_keyring_t *)netpgp.pubring, 
  1121                         (const uint8_t *)fpr, length,
  1122                         NULL)) == NULL) {
  1123 
  1124             return PEP_KEY_NOT_FOUND;
  1125         }
  1126 
  1127         result = cb(cb_arg, key);
  1128 
  1129     } else {
  1130         // Search by name for pattern. Can match many.
  1131         unsigned from = 0;
  1132         result = PEP_KEY_NOT_FOUND;
  1133         while((key = (pgp_key_t *)pgp_getnextkeybyname(
  1134                         netpgp.io,
  1135                         (pgp_keyring_t *)netpgp.pubring, 
  1136 			            (const char *)pattern,
  1137                         &from)) != NULL) {
  1138 
  1139             result = cb(cb_arg, key);
  1140             if (result != PEP_STATUS_OK)
  1141                 break;
  1142 
  1143             from++;
  1144         }
  1145     }
  1146 
  1147     return result;
  1148 }
  1149 
  1150 static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  1151 {
  1152     stringlist_t **keylist = arg;
  1153     char *newfprstr = NULL;
  1154 
  1155     fpr_to_str(&newfprstr,
  1156                key->sigfingerprint.fingerprint,
  1157                key->sigfingerprint.length);
  1158 
  1159     if (newfprstr == NULL) {
  1160         return PEP_OUT_OF_MEMORY;
  1161     } else { 
  1162 
  1163         *keylist = stringlist_add(*keylist, newfprstr);
  1164         if (*keylist == NULL) {
  1165             free(newfprstr);
  1166             return PEP_OUT_OF_MEMORY;
  1167         }
  1168     }
  1169     return PEP_STATUS_OK;
  1170 }
  1171 
  1172 PEP_STATUS pgp_find_keys(
  1173     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1174     )
  1175 {
  1176     stringlist_t *_keylist, *_k;
  1177 
  1178     PEP_STATUS result;
  1179 
  1180     assert(session);
  1181     assert(pattern);
  1182     assert(keylist);
  1183 
  1184     if (!session || !pattern || !keylist )
  1185         return PEP_UNKNOWN_ERROR;
  1186 
  1187     if(pthread_mutex_lock(&netpgp_mutex)){
  1188         return PEP_UNKNOWN_ERROR;
  1189     }
  1190 
  1191     *keylist = NULL;
  1192     _keylist = new_stringlist(NULL);
  1193     if (_k == NULL) {
  1194         result = PEP_OUT_OF_MEMORY;
  1195         goto unlock_netpgp;
  1196     }
  1197     _k = _keylist;
  1198 
  1199     result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  1200 
  1201     if (result == PEP_STATUS_OK) {
  1202         *keylist = _keylist;
  1203         // Transfer ownership, no free
  1204         goto unlock_netpgp;
  1205     }
  1206 
  1207 free_keylist:
  1208     free_stringlist(_keylist);
  1209 
  1210 unlock_netpgp:
  1211     pthread_mutex_unlock(&netpgp_mutex);
  1212 
  1213     return result;
  1214 }
  1215 
  1216 static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
  1217 {
  1218     char *newfprstr = NULL;
  1219 
  1220     fpr_to_str(&newfprstr,
  1221                key->sigfingerprint.fingerprint,
  1222                key->sigfingerprint.length);
  1223 
  1224     if (newfprstr == NULL) {
  1225         return PEP_OUT_OF_MEMORY;
  1226     } else { 
  1227 
  1228         printf("would send:\n%s\n", newfprstr);
  1229         pgp_print_keydata(netpgp.io, netpgp.pubring, key, "to send", &key->key.pubkey, 0);
  1230         free(newfprstr);
  1231     }
  1232     return PEP_STATUS_OK;
  1233 }
  1234 
  1235 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1236 {
  1237 
  1238     PEP_STATUS result;
  1239 
  1240     assert(session);
  1241     assert(pattern);
  1242 
  1243     if (!session || !pattern )
  1244         return PEP_UNKNOWN_ERROR;
  1245 
  1246     if(pthread_mutex_lock(&netpgp_mutex)){
  1247         return PEP_UNKNOWN_ERROR;
  1248     }
  1249 
  1250     result = find_keys_do(pattern, &send_key_cb, NULL);
  1251 
  1252     result = PEP_CANNOT_SEND_KEY;
  1253 unlock_netpgp:
  1254     pthread_mutex_unlock(&netpgp_mutex);
  1255 
  1256     return result;
  1257 }
  1258 
  1259 
  1260 PEP_STATUS pgp_get_key_rating(
  1261     PEP_SESSION session,
  1262     const char *fpr,
  1263     PEP_comm_type *comm_type
  1264     )
  1265 {
  1266     PEP_STATUS status = PEP_STATUS_OK;
  1267 
  1268     assert(session);
  1269     assert(fpr);
  1270     assert(comm_type);
  1271 
  1272     *comm_type = PEP_ct_unknown;
  1273 
  1274     /* TODO get key from fpr */
  1275     return PEP_UNKNOWN_ERROR;
  1276     return PEP_GET_KEY_FAILED;
  1277 
  1278     switch (/*TODO key->protocol*/ 4) {
  1279     case /* TODO  OpenPGP */0:
  1280     case /* TODO DEFAULT */1:
  1281         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1282         break;
  1283     case /* TODO CMS */2:
  1284         *comm_type = PEP_ct_CMS_unconfirmed;
  1285         break;
  1286     default:
  1287         *comm_type = PEP_ct_unknown;
  1288         return PEP_STATUS_OK;
  1289     }
  1290 
  1291         for (; 1 == 0; /* Each subkeys */ ) {
  1292             if (/* TODO length */0 < 1024)
  1293                 *comm_type = PEP_ct_key_too_short;
  1294             else if (
  1295                 (
  1296                 (   /* TODO pubkey_algo == RSA  */ 0)
  1297                 || (/* TODO pubkey_algo == RSA_E*/ 0)
  1298                 || (/* TODO pubkey_algo == RSA_S*/ 0)
  1299                 )
  1300                 && /* sk->length */0 == 1024
  1301                 )
  1302                 *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1303 
  1304             if (/* TODO invalid */ 1) {
  1305                 *comm_type = PEP_ct_key_b0rken;
  1306                 break;
  1307             }
  1308             if (/* TODO expired */ 1) {
  1309                 *comm_type = PEP_ct_key_expired;
  1310                 break;
  1311             }
  1312             if (/* TODO revoked*/ 1) {
  1313                 *comm_type = PEP_ct_key_revoked;
  1314                 break;
  1315             }
  1316         }
  1317         *comm_type = PEP_ct_unknown;
  1318         return PEP_OUT_OF_MEMORY;
  1319         return PEP_UNKNOWN_ERROR;
  1320 
  1321 
  1322     return status;
  1323 }
  1324 
  1325 PEP_STATUS pgp_renew_key(
  1326         PEP_SESSION session,
  1327         const char *fpr,
  1328         const timestamp *ts
  1329     )
  1330 {
  1331     PEP_STATUS status = PEP_STATUS_OK;
  1332     char date_text[12];
  1333 
  1334     assert(session);
  1335     assert(fpr);
  1336 
  1337     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  1338             ts->tm_mon + 1, ts->tm_mday);
  1339 
  1340 
  1341         return PEP_UNKNOWN_ERROR;
  1342     return PEP_STATUS_OK;
  1343 }
  1344 
  1345 PEP_STATUS pgp_revoke_key(
  1346         PEP_SESSION session,
  1347         const char *fpr,
  1348         const char *reason
  1349     )
  1350 {
  1351     PEP_STATUS status = PEP_STATUS_OK;
  1352     
  1353     assert(session);
  1354     assert(fpr);
  1355 
  1356         return PEP_UNKNOWN_ERROR;
  1357 
  1358     return PEP_STATUS_OK;
  1359 }
  1360 
  1361 PEP_STATUS pgp_key_expired(
  1362         PEP_SESSION session,
  1363         const char *fpr,
  1364         bool *expired
  1365     )
  1366 {
  1367     PEP_STATUS status = PEP_STATUS_OK;
  1368 
  1369     assert(session);
  1370     assert(fpr);
  1371     assert(expired);
  1372 
  1373     *expired = false;
  1374 
  1375     if (status != PEP_STATUS_OK)
  1376         return status;
  1377 
  1378     return PEP_STATUS_OK;
  1379 }
  1380