src/pgp_gpg.c
author Edouard Tisserant <edouard@pep-project.org>
Mon, 24 Jul 2017 09:56:31 -0400
branchgpgme_passphrase_cb
changeset 1940 285d5cb86dfa
parent 1938 97fcdff36aa7
permissions -rw-r--r--
ENGINE-220 passphrase_cb confirmed working with 2.1.18 and 1.8.0 (current from debian stable). Experimental code NOT TO BE MERGED !
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "platform.h"
     5 #include "pEp_internal.h"
     6 #include "pgp_gpg.h"
     7 
     8 #include <limits.h>
     9 
    10 #include "wrappers.h"
    11 
    12 #define _GPGERR(X) ((X) & 0xffffL)
    13 
    14 static void *gpgme;
    15 static struct gpg_s gpg;
    16 
    17 static bool ensure_config_values(stringlist_t *keys, stringlist_t *values, const char* config_file_path)
    18 {
    19     static char buf[MAX_LINELENGTH];
    20     int r;
    21     stringlist_t *_k;
    22     stringlist_t *_v;
    23     unsigned int i;
    24     unsigned int found = 0;
    25 
    26     FILE *f = Fopen(config_file_path, "r");
    27     if (f == NULL && errno == ENOMEM)
    28         return false;
    29 
    30     if (f != NULL) {
    31         int length = stringlist_length(keys);
    32         unsigned int n = (1 << length) - 1;
    33 
    34         // make sure we 1) have the same number of keys and values
    35         // and 2) we don't have more key/value pairs than
    36         // the size of the bitfield used to hold the indices
    37         // of key/value pairs matching keys in the config file.
    38         assert(length <= sizeof(unsigned int) * CHAR_BIT);
    39         assert(length == stringlist_length(values));
    40         if (!(length == stringlist_length(values) &&
    41               length <= sizeof(unsigned int) * CHAR_BIT)) {
    42             Fclose(f);
    43 
    44             return false;
    45         }
    46 
    47         do {
    48             char * s = Fgets(buf, MAX_LINELENGTH, f);
    49             if (!feof(f)) {
    50                 assert(s);
    51                 if (s == NULL)
    52                     return false;
    53 
    54                 if (s && !feof(f)) {
    55                     char * rest;
    56                     char * t = strtok_r(s, " ", &rest);
    57                     for (i = 1, _k = keys, _v = values; _k != NULL;
    58                             _k = _k->next, _v = _v->next, i <<= 1) {
    59                         if (t && strncmp(t, _k->value, strlen(_k->value)) == 0)
    60                             found |= i;
    61 
    62                         if (i == n) {
    63                             r = Fclose(f);
    64                             if (r != 0)
    65                                 return false;
    66                             return true;
    67                         }
    68                     }
    69                 }
    70             }
    71         } while (!feof(f));
    72         f = Freopen(config_file_path, "a", f);
    73     }
    74     else {
    75         f = Fopen(config_file_path, "w");
    76     }
    77 
    78     assert(f);
    79     if (f == NULL)
    80         return false;
    81 
    82     for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
    83             _v = _v->next, i <<= 1) {
    84         if ((found & i) == 0) {
    85             r = Fprintf(f, "%s %s\n", _k->value, _v->value);
    86             assert(r >= 0);
    87             if(r<0)
    88                 return false;
    89         }
    90     }
    91 
    92     r = Fclose(f);
    93     assert(r == 0);
    94     if (r != 0)
    95         return false;
    96 
    97     return true;
    98 }
    99 
   100 gpgme_error_t passphrase_cb(
   101 		void *hook, 
   102 		const char *uid_hint, 
   103 		const char *passphrase_info, 
   104 		int prev_was_bad, 
   105 		int fd)
   106 {
   107     printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
   108 
   109 	gpgme_error_t error = GPG_ERR_NO_ERROR; 
   110 	char *secret = "passphrase";
   111   
   112 	// to cancel :  
   113  	// return gpg_error(GPG_ERR_CANCELED);
   114     
   115 	// TODO : use hook to retrieve client session
   116 	// TODO : call adapter's client passphrase callback
   117 
   118         size_t len = strlen(secret);
   119         size_t cursor = 0;
   120         do {
   121         	ssize_t wres = gpg.gpgme_io_write(fd, secret + cursor, len - cursor);
   122         	if (wres < 0) {
   123         		error = gpg.gpgme_error_from_errno(errno);
   124         		goto exit_free;
   125         		break;
   126         	}
   127         	cursor += wres;
   128         } while ( cursor < len );
   129 
   130 	gpg.gpgme_io_write( fd, "\n", 1 );
   131 
   132 exit_free:
   133 	//free(secret);
   134 	return error;
   135 }
   136 
   137 PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   138 {
   139     PEP_STATUS status = PEP_STATUS_OK;
   140     gpgme_error_t gpgme_error;
   141     bool bResult;
   142 
   143     if (in_first) {
   144         stringlist_t *conf_keys   = new_stringlist("keyserver");
   145         stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
   146 
   147         stringlist_add(conf_keys, "cert-digest-algo");
   148         stringlist_add(conf_values, "SHA256");
   149 
   150         stringlist_add(conf_keys, "no-emit-version");
   151         stringlist_add(conf_values, "");
   152 
   153         stringlist_add(conf_keys, "no-comments");
   154         stringlist_add(conf_values, "");
   155 
   156         stringlist_add(conf_keys, "personal-cipher-preferences");
   157         stringlist_add(conf_values, "AES AES256 AES192 CAST5");
   158 
   159         stringlist_add(conf_keys, "personal-digest-preferences");
   160         stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
   161 
   162         stringlist_add(conf_keys, "ignore-time-conflict");
   163         stringlist_add(conf_values, "");
   164 
   165         bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
   166 
   167         free_stringlist(conf_keys);
   168         free_stringlist(conf_values);
   169 
   170         assert(bResult);
   171         if(!bResult){
   172             status = PEP_INIT_NO_GPG_HOME;
   173             goto pep_error;
   174         }
   175 
   176         conf_keys = new_stringlist("default-cache-ttl");
   177         conf_values = new_stringlist("300");
   178 
   179         stringlist_add(conf_keys, "max-cache-ttl");
   180         stringlist_add(conf_values, "1200");
   181 
   182         bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf());
   183 
   184         free_stringlist(conf_keys);
   185         free_stringlist(conf_values);
   186 
   187         assert(bResult);
   188         if(!bResult){
   189             status = PEP_INIT_NO_GPG_HOME; /* FIXME: Wrong error here? */
   190             goto pep_error;
   191         }
   192 
   193         gpgme = dlopen(LIBGPGME, RTLD_LAZY);
   194         if (gpgme == NULL) {
   195             status = PEP_INIT_CANNOT_LOAD_GPGME;
   196             goto pep_error;
   197         }
   198 
   199         memset(&gpg, 0, sizeof(struct gpg_s));
   200 
   201         gpg.gpgme_set_locale
   202             = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
   203             "gpgme_set_locale");
   204         assert(gpg.gpgme_set_locale);
   205 
   206         gpg.gpgme_check
   207             = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
   208             "gpgme_check_version");
   209         assert(gpg.gpgme_check);
   210 
   211         gpg.gpgme_new
   212             = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
   213         assert(gpg.gpgme_new);
   214 
   215         gpg.gpgme_release
   216             = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
   217         assert(gpg.gpgme_release);
   218 
   219         gpg.gpgme_get_engine_info
   220             = (gpgme_get_engine_info_t) (intptr_t) dlsym(gpgme,
   221             "gpgme_get_engine_info");
   222         assert(gpg.gpgme_get_engine_info);
   223 
   224         gpg.gpgme_set_protocol
   225             = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
   226             "gpgme_set_protocol");
   227         assert(gpg.gpgme_set_protocol);
   228 
   229         gpg.gpgme_set_armor
   230             = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
   231             "gpgme_set_armor");
   232         assert(gpg.gpgme_set_armor);
   233 
   234         gpg.gpgme_data_new
   235             = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
   236             "gpgme_data_new");
   237         assert(gpg.gpgme_data_new);
   238 
   239         gpg.gpgme_data_new_from_mem
   240             = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
   241             "gpgme_data_new_from_mem");
   242         assert(gpg.gpgme_data_new_from_mem);
   243 
   244         gpg.gpgme_data_new_from_cbs
   245             = (gpgme_data_new_from_cbs_t) (intptr_t) dlsym(gpgme,
   246             "gpgme_data_new_from_cbs");
   247         assert(gpg.gpgme_data_new_from_cbs);
   248 
   249         gpg.gpgme_data_release
   250             = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
   251             "gpgme_data_release");
   252         assert(gpg.gpgme_data_release);
   253 
   254         gpg.gpgme_data_identify
   255             = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
   256             "gpgme_data_identify");
   257         assert(gpg.gpgme_data_identify);
   258 
   259         gpg.gpgme_data_seek
   260             = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
   261             "gpgme_data_seek");
   262         assert(gpg.gpgme_data_seek);
   263 
   264         gpg.gpgme_data_read
   265             = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
   266             "gpgme_data_read");
   267         assert(gpg.gpgme_data_read);
   268 
   269         gpg.gpgme_error_from_errno
   270             = (gpgme_error_from_errno_t) (intptr_t) dlsym(gpgme,
   271             "gpgme_error_from_errno");
   272         assert(gpg.gpgme_error_from_errno);
   273 
   274         gpg.gpgme_op_decrypt
   275             = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
   276             "gpgme_op_decrypt");
   277         assert(gpg.gpgme_op_decrypt);
   278 
   279         gpg.gpgme_op_verify
   280             = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
   281             "gpgme_op_verify");
   282         assert(gpg.gpgme_op_verify);
   283 
   284         gpg.gpgme_op_decrypt_verify
   285             = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
   286             "gpgme_op_decrypt_verify");
   287         assert(gpg.gpgme_op_decrypt_verify);
   288 
   289         gpg.gpgme_op_decrypt_result
   290             = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
   291             "gpgme_op_decrypt_result");
   292         assert(gpg.gpgme_op_decrypt_result);
   293 
   294         gpg.gpgme_op_encrypt_sign
   295             = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
   296             "gpgme_op_encrypt_sign");
   297         assert(gpg.gpgme_op_encrypt_sign);
   298 
   299         gpg.gpgme_op_encrypt
   300             = (gpgme_op_encrypt_t) (intptr_t) dlsym(gpgme,
   301             "gpgme_op_encrypt");
   302         assert(gpg.gpgme_op_encrypt);
   303 
   304         gpg.gpgme_op_verify_result
   305             = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
   306             "gpgme_op_verify_result");
   307         assert(gpg.gpgme_op_verify_result);
   308 
   309         gpg.gpgme_signers_clear
   310             = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
   311             "gpgme_signers_clear");
   312         assert(gpg.gpgme_signers_clear);
   313 
   314         gpg.gpgme_signers_add
   315             = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
   316             "gpgme_signers_add");
   317         assert(gpg.gpgme_signers_add);
   318 
   319         gpg.gpgme_set_passphrase_cb
   320             = (gpgme_set_passphrase_cb_t) (intptr_t) dlsym(gpgme,
   321             "gpgme_set_passphrase_cb");
   322         assert(gpg.gpgme_set_passphrase_cb);
   323 
   324         gpg.gpgme_set_pinentry_mode
   325             = (gpgme_set_pinentry_mode_t) (intptr_t) dlsym(gpgme,
   326             "gpgme_set_pinentry_mode");
   327         assert(gpg.gpgme_set_pinentry_mode);
   328 
   329         gpg.gpgme_get_key
   330             = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
   331         assert(gpg.gpgme_get_key);
   332         
   333         #ifdef GPGME_VERSION_NUMBER 
   334         #if (GPGME_VERSION_NUMBER >= 0x010700)
   335                 gpg.gpgme_op_createkey
   336                     = (gpgme_op_createkey_t) (intptr_t) dlsym(gpgme,
   337                     "gpgme_op_createkey");
   338                 assert(gpg.gpgme_op_createkey);
   339                 
   340                 gpg.gpgme_op_createsubkey
   341                     = (gpgme_op_createsubkey_t) (intptr_t) dlsym(gpgme,
   342                     "gpgme_op_createsubkey");
   343                 assert(gpg.gpgme_op_createsubkey);
   344 
   345         #endif
   346         #endif
   347         
   348         gpg.gpgme_op_genkey
   349             = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
   350             "gpgme_op_genkey");
   351         assert(gpg.gpgme_op_genkey);
   352 
   353         gpg.gpgme_op_genkey_result
   354             = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
   355             "gpgme_op_genkey_result");
   356         assert(gpg.gpgme_op_genkey_result);
   357 
   358         gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
   359             dlsym(gpgme, "gpgme_op_delete");
   360         assert(gpg.gpgme_op_delete);
   361 
   362         gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
   363             dlsym(gpgme, "gpgme_op_import");
   364         assert(gpg.gpgme_op_import);
   365 
   366         gpg.gpgme_op_import_result
   367             = (gpgme_op_import_result_t) (intptr_t) dlsym(gpgme,
   368             "gpgme_op_import_result");
   369         assert(gpg.gpgme_op_import_result);
   370 
   371         gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
   372             dlsym(gpgme, "gpgme_op_export");
   373         assert(gpg.gpgme_op_export);
   374 
   375         gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
   376             dlsym(gpgme, "gpgme_set_keylist_mode");
   377         assert(gpg.gpgme_set_keylist_mode);
   378 
   379         gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
   380             dlsym(gpgme, "gpgme_get_keylist_mode");
   381         assert(gpg.gpgme_get_keylist_mode);
   382 
   383         gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
   384             dlsym(gpgme, "gpgme_op_keylist_start");
   385         assert(gpg.gpgme_op_keylist_start);
   386 
   387         gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
   388             dlsym(gpgme, "gpgme_op_keylist_next");
   389         assert(gpg.gpgme_op_keylist_next);
   390 
   391         gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
   392             dlsym(gpgme, "gpgme_op_keylist_end");
   393         assert(gpg.gpgme_op_keylist_end);
   394 
   395         gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
   396             dlsym(gpgme, "gpgme_op_import_keys");
   397         assert(gpg.gpgme_op_import_keys);
   398 
   399         gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
   400             dlsym(gpgme, "gpgme_key_ref");
   401         assert(gpg.gpgme_key_ref);
   402 
   403         gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
   404             dlsym(gpgme, "gpgme_key_unref");
   405         assert(gpg.gpgme_key_unref);
   406 
   407 		gpg.gpgme_key_release = (gpgme_key_release_t)(intptr_t)
   408 			dlsym(gpgme, "gpgme_key_release");
   409 		assert(gpg.gpgme_key_release);
   410 
   411         gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
   412             dlsym(gpgme, "gpgme_op_edit");
   413         assert(gpg.gpgme_op_edit);
   414 
   415         gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
   416             dlsym(gpgme, "gpgme_io_write");
   417         assert(gpg.gpgme_io_write);
   418 
   419         gpg.version = gpg.gpgme_check(NULL);
   420 
   421         const char * const cLocal = setlocale(LC_ALL, NULL);
   422         if (!cLocal || (strcmp(cLocal, "C") == 0))
   423             setlocale(LC_ALL, "");
   424 
   425         gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
   426 #ifdef LC_MESSAGES // Windoze
   427         gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
   428 #endif
   429     }
   430 
   431     gpg.gpgme_check(NULL);
   432     gpgme_error = gpg.gpgme_new(&session->ctx);
   433     gpgme_error = _GPGERR(gpgme_error);
   434     if (gpgme_error != GPG_ERR_NO_ERROR) {
   435         status = PEP_INIT_GPGME_INIT_FAILED;
   436         goto pep_error;
   437     }
   438     assert(session->ctx);
   439 
   440     gpgme_engine_info_t info;
   441     int err = gpg.gpgme_get_engine_info(&info);
   442     assert(err == GPG_ERR_NO_ERROR);
   443     if (err != GPG_ERR_NO_ERROR) {
   444         status = PEP_OUT_OF_MEMORY;
   445         goto pep_error;
   446     }
   447 
   448     DEBUG_LOG("GPGME init", "gpg version", info->version);
   449 
   450     gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
   451     gpgme_error = _GPGERR(gpgme_error);
   452     assert(gpgme_error == GPG_ERR_NO_ERROR);
   453 
   454     gpgme_error = gpg.gpgme_set_passphrase_cb(session->ctx, passphrase_cb, NULL);
   455     gpgme_error = _GPGERR(gpgme_error);
   456     assert(gpgme_error == GPG_ERR_NO_ERROR);
   457 
   458     // Enabling Loopback Mode Pinentry crashes gpg 2.0.30 at op_decrypt*
   459     // while it works with 2.1.17. Arbitrarily disable it for <=2.0
   460     if(strncmp(info->version, "2.0", 3) > 0) {
   461         gpgme_error = gpg.gpgme_set_pinentry_mode(session->ctx, GPGME_PINENTRY_MODE_LOOPBACK);
   462         gpgme_error = _GPGERR(gpgme_error);
   463         assert(gpgme_error == GPG_ERR_NO_ERROR);
   464     }
   465 
   466     gpg.gpgme_set_armor(session->ctx, 1);
   467 
   468     return PEP_STATUS_OK;
   469 
   470 pep_error:
   471     pgp_release(session, in_first);
   472     return status;
   473 }
   474 
   475 void pgp_release(PEP_SESSION session, bool out_last)
   476 {
   477     if (session->ctx) {
   478         gpg.gpgme_release(session->ctx);
   479         session->ctx = NULL;
   480     }
   481 
   482     if (out_last)
   483         if (gpgme)
   484             dlclose(gpgme);
   485 }
   486 
   487 PEP_STATUS pgp_decrypt_and_verify(
   488     PEP_SESSION session, const char *ctext, size_t csize,
   489     const char *dsigtext, size_t dsigsize,
   490     char **ptext, size_t *psize, stringlist_t **keylist
   491     )
   492 {
   493     PEP_STATUS result;
   494     gpgme_error_t gpgme_error;
   495     gpgme_data_t cipher, plain;
   496     gpgme_data_type_t dt;
   497     gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
   498 
   499     stringlist_t *_keylist = NULL;
   500     //int i_key = 0;
   501 
   502     assert(session);
   503     assert(ctext);
   504     assert(csize);
   505     assert(ptext);
   506     assert(psize);
   507     assert(keylist);
   508 
   509     *ptext = NULL;
   510     *psize = 0;
   511     *keylist = NULL;
   512 
   513     gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
   514     gpgme_error = _GPGERR(gpgme_error);
   515     assert(gpgme_error == GPG_ERR_NO_ERROR);
   516     if (gpgme_error != GPG_ERR_NO_ERROR) {
   517         if (gpgme_error == GPG_ERR_ENOMEM)
   518             return PEP_OUT_OF_MEMORY;
   519         else
   520             return PEP_UNKNOWN_ERROR;
   521     }
   522 
   523     gpgme_error = gpg.gpgme_data_new(&plain);
   524     gpgme_error = _GPGERR(gpgme_error);
   525     assert(gpgme_error == GPG_ERR_NO_ERROR);
   526     if (gpgme_error != GPG_ERR_NO_ERROR) {
   527         gpg.gpgme_data_release(cipher);
   528         if (gpgme_error == GPG_ERR_ENOMEM)
   529             return PEP_OUT_OF_MEMORY;
   530         else
   531             return PEP_UNKNOWN_ERROR;
   532     }
   533 
   534 
   535     dt = gpg.gpgme_data_identify(cipher);
   536     switch (dt) {
   537 #if GPGME_VERSION_NUMBER > 0x010600
   538     case GPGME_DATA_TYPE_PGP_ENCRYPTED:
   539 #endif
   540     case GPGME_DATA_TYPE_PGP_SIGNED:
   541     case GPGME_DATA_TYPE_PGP_OTHER:
   542         if (dsigtext) {
   543             gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
   544         }
   545         else {
   546             gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
   547                 plain);
   548         }
   549         gpgme_error = _GPGERR(gpgme_error);
   550         assert(gpgme_error != GPG_ERR_INV_VALUE);
   551         assert(gpgme_error != GPG_ERR_NO_DATA);
   552 
   553         switch (gpgme_error) {
   554             case GPG_ERR_NO_ERROR:
   555             {
   556                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   557                 /* NOW is when we have to process the decrypt_result, period.
   558                    it is only valid until the next call on the context. */
   559                    
   560                 gpgme_key_t key;
   561                 memset(&key,0,sizeof(key));
   562                 stringlist_t* recipient_keylist = new_stringlist(NULL);
   563                 if (!recipient_keylist) {
   564                     gpg.gpgme_data_release(plain);
   565                     gpg.gpgme_data_release(cipher);
   566                     if (recipient_keylist)
   567                         free_stringlist(recipient_keylist);
   568                     return PEP_OUT_OF_MEMORY;
   569                 }
   570                
   571                 if (gpgme_decrypt_result != NULL) {
   572                     stringlist_t* _keylist = recipient_keylist;
   573                     for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   574                         // GPGME may give subkey's fpr instead of primary key's fpr.
   575                         // Therefore we ask for the primary fingerprint instead
   576                         // we assume that gpgme_get_key can find key by subkey's fpr
   577                         gpgme_error = gpg.gpgme_get_key(session->ctx,
   578                             r->keyid, &key, 0);
   579                         gpgme_error = _GPGERR(gpgme_error);
   580                         assert(gpgme_error != GPG_ERR_ENOMEM);
   581                         if (gpgme_error == GPG_ERR_ENOMEM) {
   582                             free_stringlist(_keylist);
   583                             result = PEP_OUT_OF_MEMORY;
   584                         }
   585                         // Primary key is given as the first subkey
   586                         if (gpgme_error == GPG_ERR_NO_ERROR &&
   587                             key && key->subkeys && key->subkeys->fpr
   588                             && key->subkeys->fpr[0]) {
   589                             _keylist = stringlist_add(_keylist, key->subkeys->fpr);
   590  
   591                             gpg.gpgme_key_unref(key);
   592  
   593                         }
   594                     }
   595                     assert(_keylist);
   596                     if (_keylist == NULL) {
   597                         free_stringlist(recipient_keylist);
   598                         if (*keylist)
   599                             free_stringlist(*keylist);
   600                         *keylist = NULL;
   601                         result = PEP_OUT_OF_MEMORY;
   602                     }
   603                 } /* Ok, so now we have any recipients it was encrypted for
   604                      in recipient_keylist */
   605             
   606                    
   607                 gpgme_verify_result_t gpgme_verify_result;
   608                 char *_buffer = NULL;
   609                 size_t reading;
   610                 size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
   611                 gpgme_signature_t gpgme_signature;
   612 
   613                 assert(length != -1);
   614                 gpg.gpgme_data_seek(plain, 0, SEEK_SET);
   615 
   616                 // TODO: make things less memory consuming
   617                 // the following algorithm allocates memory for the complete
   618                 // text
   619 
   620                 _buffer = malloc(length + 1);
   621                 assert(_buffer);
   622                 if (_buffer == NULL) {
   623                     gpg.gpgme_data_release(plain);
   624                     gpg.gpgme_data_release(cipher);
   625                     if (recipient_keylist)
   626                         free_stringlist(recipient_keylist);
   627                     return PEP_OUT_OF_MEMORY;
   628                 }
   629 
   630                 reading = gpg.gpgme_data_read(plain, _buffer, length);
   631                 assert(length == reading);
   632 
   633                 if (dsigtext) {  // Is this safe to do?
   634                     gpgme_data_t sigdata;
   635                     gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
   636                                                 dsigsize, 0);
   637                     gpg.gpgme_op_verify(session->ctx, sigdata, plain, NULL);
   638                     gpg.gpgme_data_release(sigdata);
   639                 }
   640 
   641                 gpgme_verify_result =
   642                     gpg.gpgme_op_verify_result(session->ctx);
   643                 assert(gpgme_verify_result);
   644                 gpgme_signature = gpgme_verify_result->signatures;
   645 
   646                 if (!gpgme_signature) {
   647                     // try cleartext sig verification
   648                     gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
   649                     gpgme_verify_result =
   650                         gpg.gpgme_op_verify_result(session->ctx);
   651                             assert(gpgme_verify_result);
   652                     gpgme_signature = gpgme_verify_result->signatures;                    
   653                 }
   654 
   655                 if (gpgme_signature) {
   656                     stringlist_t *k;
   657                     _keylist = new_stringlist(NULL);
   658                     assert(_keylist);
   659                     if (_keylist == NULL) {
   660                         gpg.gpgme_data_release(plain);
   661                         gpg.gpgme_data_release(cipher);
   662                         free(_buffer);
   663                         return PEP_OUT_OF_MEMORY;
   664                     }
   665                     k = _keylist;
   666 
   667                     result = PEP_DECRYPTED_AND_VERIFIED;
   668                     gpg.gpgme_check(NULL);
   669                     do { /* get all signers and put them at the front off
   670                             the keylist (likely only one) */
   671                         switch (_GPGERR(gpgme_signature->status)) {
   672                         case GPG_ERR_NO_ERROR:
   673                         {
   674                             // Some versions of gpg returns signer's
   675                             // signing subkey fingerprint instead of
   676                             // signer's primary key fingerprint.
   677                             // This is meant to get signer's primary
   678                             // key fingerprint, using subkey's.
   679 
   680                             gpgme_key_t key = NULL;
   681 
   682                             gpgme_error = gpg.gpgme_get_key(session->ctx,
   683                                 gpgme_signature->fpr, &key, 0);
   684                             gpgme_error = _GPGERR(gpgme_error);
   685                             assert(gpgme_error != GPG_ERR_ENOMEM);
   686                             if (gpgme_error == GPG_ERR_ENOMEM) {
   687                                 free_stringlist(_keylist);
   688                                 gpg.gpgme_data_release(plain);
   689                                 gpg.gpgme_data_release(cipher);
   690                                 free(_buffer);
   691                                 return PEP_OUT_OF_MEMORY;
   692                             }
   693                             // Primary key is given as the first subkey
   694                             if (gpgme_error == GPG_ERR_NO_ERROR &&
   695                                 key && key->subkeys && key->subkeys->fpr
   696                                 && key->subkeys->fpr[0])
   697                             {
   698                                 k = stringlist_add(k, key->subkeys->fpr);
   699 
   700                                 gpg.gpgme_key_unref(key);
   701 
   702                                 if (k == NULL) {
   703                                     free_stringlist(_keylist);
   704                                     if (recipient_keylist)
   705                                         free (recipient_keylist);
   706                                     gpg.gpgme_data_release(plain);
   707                                     gpg.gpgme_data_release(cipher);
   708                                     free(_buffer);
   709                                     return PEP_OUT_OF_MEMORY;
   710                                 }
   711                             }
   712                             else
   713                             {
   714                                 result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   715                                 break;
   716                             }
   717                             break;
   718                         }
   719                         case GPG_ERR_CERT_REVOKED:
   720                         case GPG_ERR_BAD_SIGNATURE:
   721                             result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   722                             break;
   723                         case GPG_ERR_SIG_EXPIRED:
   724                         case GPG_ERR_KEY_EXPIRED:
   725                         case GPG_ERR_NO_PUBKEY:
   726                             k = stringlist_add(k, gpgme_signature->fpr);
   727                             if (k == NULL) {
   728                                 free_stringlist(_keylist);
   729                                 if (recipient_keylist)
   730                                     free_stringlist(recipient_keylist);
   731                                 gpg.gpgme_data_release(plain);
   732                                 gpg.gpgme_data_release(cipher);
   733                                 free(_buffer);
   734                                 return PEP_OUT_OF_MEMORY;
   735                             }
   736                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   737                                 result = PEP_DECRYPTED;
   738                             break;
   739                         case GPG_ERR_GENERAL:
   740                             break;
   741                         default:
   742                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   743                                 result = PEP_DECRYPTED;
   744                             break;
   745                         }
   746                     } while ((gpgme_signature = gpgme_signature->next));
   747                 }
   748                 else {
   749                     result = PEP_DECRYPTED;
   750                 }
   751 
   752                 if (result == PEP_DECRYPTED_AND_VERIFIED
   753                     || result == PEP_DECRYPTED) {
   754                     *ptext = _buffer;
   755                     *psize = reading;
   756                     (*ptext)[*psize] = 0; // safeguard for naive users
   757                     *keylist = _keylist;
   758                     if (recipient_keylist) {
   759                         if (!_keylist)
   760                             *keylist = new_stringlist(""); // no sig 
   761                         if (!(*keylist)) {
   762                             free_stringlist(_keylist);
   763                             if (recipient_keylist)
   764                                 free_stringlist(recipient_keylist);
   765                             gpg.gpgme_data_release(plain);
   766                             gpg.gpgme_data_release(cipher);
   767                             free(_buffer);
   768                             return PEP_OUT_OF_MEMORY;
   769                         }    
   770                         stringlist_append(*keylist, recipient_keylist);
   771                     }
   772                 }
   773                 else {
   774                     free_stringlist(_keylist);
   775                     if (recipient_keylist)
   776                         free_stringlist(recipient_keylist);
   777                     free(_buffer);
   778                 }
   779                 break;
   780             }
   781             case GPG_ERR_BAD_PASSPHRASE:
   782                 result = PEP_DECRYPT_NO_KEY;
   783                 break;
   784             case GPG_ERR_DECRYPT_FAILED:
   785             default:
   786             {
   787                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   788                 result = PEP_DECRYPT_NO_KEY;
   789 
   790                 if (gpgme_decrypt_result != NULL) {
   791                     if (gpgme_decrypt_result->unsupported_algorithm)
   792                         *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   793                     else
   794                         *keylist = new_stringlist("");
   795                     assert(*keylist);
   796                     if (*keylist == NULL) {
   797                         result = PEP_OUT_OF_MEMORY;
   798                         break;
   799                     }
   800                 }
   801             }
   802         }
   803         break;
   804 
   805     default:
   806         result = PEP_DECRYPT_WRONG_FORMAT;
   807     }
   808 
   809     gpg.gpgme_data_release(plain);
   810     gpg.gpgme_data_release(cipher);
   811     return result;
   812 }
   813 
   814 PEP_STATUS pgp_verify_text(
   815     PEP_SESSION session, const char *text, size_t size,
   816     const char *signature, size_t sig_size, stringlist_t **keylist
   817     )
   818 {
   819     PEP_STATUS result;
   820     gpgme_error_t gpgme_error;
   821     gpgme_data_t d_text, d_sig;
   822     stringlist_t *_keylist;
   823 
   824     assert(session);
   825     assert(text);
   826     assert(size);
   827     assert(signature);
   828     assert(sig_size);
   829     assert(keylist);
   830 
   831     *keylist = NULL;
   832 
   833     gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   834     gpgme_error = _GPGERR(gpgme_error);
   835     assert(gpgme_error == GPG_ERR_NO_ERROR);
   836     if (gpgme_error != GPG_ERR_NO_ERROR) {
   837         if (gpgme_error == GPG_ERR_ENOMEM)
   838             return PEP_OUT_OF_MEMORY;
   839         else
   840             return PEP_UNKNOWN_ERROR;
   841     }
   842 
   843     gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   844     gpgme_error = _GPGERR(gpgme_error);
   845     assert(gpgme_error == GPG_ERR_NO_ERROR);
   846     if (gpgme_error != GPG_ERR_NO_ERROR) {
   847         gpg.gpgme_data_release(d_text);
   848         if (gpgme_error == GPG_ERR_ENOMEM)
   849             return PEP_OUT_OF_MEMORY;
   850         else
   851             return PEP_UNKNOWN_ERROR;
   852     }
   853 
   854     gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
   855     gpgme_error = _GPGERR(gpgme_error);
   856     assert(gpgme_error != GPG_ERR_INV_VALUE);
   857 
   858     switch (gpgme_error) {
   859     case GPG_ERR_NO_ERROR:
   860     {
   861         gpgme_verify_result_t gpgme_verify_result;
   862         gpgme_signature_t gpgme_signature;
   863 
   864         gpgme_verify_result =
   865             gpg.gpgme_op_verify_result(session->ctx);
   866         assert(gpgme_verify_result);
   867         gpgme_signature = gpgme_verify_result->signatures;
   868 
   869         if (gpgme_signature) {
   870             stringlist_t *k;
   871             _keylist = new_stringlist(NULL);
   872             assert(_keylist);
   873             if (_keylist == NULL) {
   874                 gpg.gpgme_data_release(d_text);
   875                 gpg.gpgme_data_release(d_sig);
   876                 return PEP_OUT_OF_MEMORY;
   877             }
   878             k = _keylist;
   879 
   880             result = PEP_VERIFIED;
   881             do {
   882                 gpgme_key_t key;
   883                 memset(&key,0,sizeof(key));
   884 
   885                 // GPGME may give subkey's fpr instead of primary key's fpr.
   886                 // Therefore we ask for the primary fingerprint instead
   887                 // we assume that gpgme_get_key can find key by subkey's fpr
   888                 gpgme_error = gpg.gpgme_get_key(session->ctx,
   889                     gpgme_signature->fpr, &key, 0);
   890                 gpgme_error = _GPGERR(gpgme_error);
   891                 assert(gpgme_error != GPG_ERR_ENOMEM);
   892                 if (gpgme_error == GPG_ERR_ENOMEM) {
   893                     free_stringlist(_keylist);
   894                     gpg.gpgme_data_release(d_text);
   895                     gpg.gpgme_data_release(d_sig);
   896                     return PEP_OUT_OF_MEMORY;
   897                 }
   898                 // Primary key is given as the first subkey
   899                 if (gpgme_error == GPG_ERR_NO_ERROR &&
   900                     key && key->subkeys && key->subkeys->fpr
   901                     && key->subkeys->fpr[0])
   902                 {
   903                     k = stringlist_add(k, key->subkeys->fpr);
   904 
   905                     gpg.gpgme_key_unref(key);
   906 
   907                     if (k == NULL) {
   908                         free_stringlist(_keylist);
   909                         gpg.gpgme_data_release(d_text);
   910                         gpg.gpgme_data_release(d_sig);
   911                         return PEP_OUT_OF_MEMORY;
   912                     }
   913                 }
   914                 else {
   915                     result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   916                     break;
   917                 }
   918 
   919                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   920                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   921                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   922                         if (result == PEP_VERIFIED
   923                             || result == PEP_VERIFIED_AND_TRUSTED)
   924                             result = PEP_UNENCRYPTED;
   925                     }
   926                     else {
   927                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   928                         break;
   929                     }
   930                 }
   931                 else {
   932                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   933                         if (result == PEP_VERIFIED)
   934                             result = PEP_VERIFIED_AND_TRUSTED;
   935                     }
   936                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   937                         // good
   938                     }
   939                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   940                         result = PEP_VERIFY_NO_KEY;
   941                     }
   942                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   943                         if (result == PEP_VERIFIED
   944                             || result == PEP_VERIFIED_AND_TRUSTED)
   945                             result = PEP_UNENCRYPTED;
   946                     }
   947                     else {
   948                         // do nothing
   949                     }
   950                 }
   951             } while ((gpgme_signature = gpgme_signature->next));
   952             *keylist = _keylist;
   953         }
   954         else {
   955             result = PEP_UNENCRYPTED;
   956         }
   957         break;
   958     }
   959         break;
   960     case GPG_ERR_NO_DATA:
   961         result = PEP_DECRYPT_WRONG_FORMAT;
   962         break;
   963     case GPG_ERR_INV_VALUE:
   964     default:
   965         result = PEP_UNKNOWN_ERROR;
   966         break;
   967     }
   968 
   969     gpg.gpgme_data_release(d_text);
   970     gpg.gpgme_data_release(d_sig);
   971 
   972     return result;
   973 }
   974 
   975 
   976 static PEP_STATUS pgp_encrypt_sign_optional(    
   977     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   978     size_t psize, char **ctext, size_t *csize, bool sign
   979 )
   980 {    
   981     PEP_STATUS result;
   982     gpgme_error_t gpgme_error;
   983     gpgme_data_t plain, cipher;
   984     gpgme_key_t *rcpt;
   985     gpgme_encrypt_flags_t flags;
   986     const stringlist_t *_keylist;
   987     int i, j;
   988 
   989     assert(session);
   990     assert(keylist);
   991     assert(ptext);
   992     assert(psize);
   993     assert(ctext);
   994     assert(csize);
   995 
   996     *ctext = NULL;
   997     *csize = 0;
   998 
   999     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
  1000     gpgme_error = _GPGERR(gpgme_error);
  1001     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1002     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1003         if (gpgme_error == GPG_ERR_ENOMEM)
  1004             return PEP_OUT_OF_MEMORY;
  1005         else
  1006             return PEP_UNKNOWN_ERROR;
  1007     }
  1008 
  1009     gpgme_error = gpg.gpgme_data_new(&cipher);
  1010     gpgme_error = _GPGERR(gpgme_error);
  1011     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1012     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1013         gpg.gpgme_data_release(plain);
  1014         if (gpgme_error == GPG_ERR_ENOMEM)
  1015             return PEP_OUT_OF_MEMORY;
  1016         else
  1017             return PEP_UNKNOWN_ERROR;
  1018     }
  1019 
  1020     rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
  1021     assert(rcpt);
  1022     if (rcpt == NULL) {
  1023         gpg.gpgme_data_release(plain);
  1024         gpg.gpgme_data_release(cipher);
  1025         return PEP_OUT_OF_MEMORY;
  1026     }
  1027 
  1028     gpg.gpgme_signers_clear(session->ctx);
  1029 
  1030     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
  1031         assert(_keylist->value);
  1032         gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
  1033             &rcpt[i], 0);
  1034         gpgme_error = _GPGERR(gpgme_error);
  1035         assert(gpgme_error != GPG_ERR_ENOMEM);
  1036 
  1037         switch (gpgme_error) {
  1038         case GPG_ERR_ENOMEM:
  1039             for (j = 0; j<i; j++)
  1040                 gpg.gpgme_key_unref(rcpt[j]);
  1041             free(rcpt);
  1042             gpg.gpgme_data_release(plain);
  1043             gpg.gpgme_data_release(cipher);
  1044             return PEP_OUT_OF_MEMORY;
  1045         case GPG_ERR_NO_ERROR:
  1046             if (i == 0 && sign) {
  1047                 gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
  1048                 _gpgme_error = _GPGERR(_gpgme_error);
  1049                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
  1050             }
  1051             break;
  1052         case GPG_ERR_EOF:
  1053             for (j = 0; j<i; j++)
  1054                 gpg.gpgme_key_unref(rcpt[j]);
  1055             free(rcpt);
  1056             gpg.gpgme_data_release(plain);
  1057             gpg.gpgme_data_release(cipher);
  1058             return PEP_KEY_NOT_FOUND;
  1059         case GPG_ERR_AMBIGUOUS_NAME:
  1060             for (j = 0; j<i; j++)
  1061                 gpg.gpgme_key_unref(rcpt[j]);
  1062             free(rcpt);
  1063             gpg.gpgme_data_release(plain);
  1064             gpg.gpgme_data_release(cipher);
  1065             return PEP_KEY_HAS_AMBIG_NAME;
  1066         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
  1067             // FPR is not a fingerprint or key ID
  1068             for (j = 0; j<i; j++)
  1069                 gpg.gpgme_key_unref(rcpt[j]);
  1070             free(rcpt);
  1071             gpg.gpgme_data_release(plain);
  1072             gpg.gpgme_data_release(cipher);
  1073             return PEP_GET_KEY_FAILED;
  1074         }
  1075     }
  1076 
  1077     // TODO: remove that and replace with proper key management
  1078     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
  1079     
  1080     if (sign) {
  1081         gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
  1082             plain, cipher);
  1083     }
  1084     else {
  1085         gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
  1086             plain, cipher);
  1087     }
  1088     
  1089     gpgme_error = _GPGERR(gpgme_error);
  1090     switch (gpgme_error) {
  1091     case GPG_ERR_NO_ERROR:
  1092     {
  1093         char *_buffer = NULL;
  1094         size_t reading;
  1095         size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
  1096         assert(length != -1);
  1097         gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
  1098 
  1099         // TODO: make things less memory consuming
  1100         // the following algorithm allocates a buffer for the complete text
  1101 
  1102         _buffer = malloc(length + 1);
  1103         assert(_buffer);
  1104         if (_buffer == NULL) {
  1105             for (j = 0; j<stringlist_length(keylist); j++)
  1106                 gpg.gpgme_key_unref(rcpt[j]);
  1107             free(rcpt);
  1108             gpg.gpgme_data_release(plain);
  1109             gpg.gpgme_data_release(cipher);
  1110             return PEP_OUT_OF_MEMORY;
  1111         }
  1112 
  1113         reading = gpg.gpgme_data_read(cipher, _buffer, length);
  1114         assert(length == reading);
  1115 
  1116         *ctext = _buffer;
  1117         *csize = reading;
  1118         (*ctext)[*csize] = 0; // safeguard for naive users
  1119         result = PEP_STATUS_OK;
  1120         break;
  1121     }
  1122     default:
  1123         result = PEP_UNKNOWN_ERROR;
  1124     }
  1125 
  1126     for (j = 0; j<stringlist_length(keylist); j++)
  1127         gpg.gpgme_key_unref(rcpt[j]);
  1128     free(rcpt);
  1129     gpg.gpgme_data_release(plain);
  1130     gpg.gpgme_data_release(cipher);
  1131     return result;
  1132 }
  1133 
  1134 PEP_STATUS pgp_encrypt_only(
  1135     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1136     size_t psize, char **ctext, size_t *csize
  1137     )
  1138 {
  1139     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1140         psize, ctext, csize, false);
  1141 }
  1142 
  1143 PEP_STATUS pgp_encrypt_and_sign(
  1144     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1145     size_t psize, char **ctext, size_t *csize
  1146     )
  1147 {
  1148     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1149         psize, ctext, csize, true);
  1150 }
  1151 
  1152 
  1153 static PEP_STATUS find_single_key(
  1154         PEP_SESSION session,
  1155         const char *fpr,
  1156         gpgme_key_t *key
  1157     )
  1158 {
  1159     gpgme_error_t gpgme_error;
  1160 
  1161     *key = NULL;
  1162 
  1163 //    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1164 
  1165     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, key, 0);
  1166 
  1167     gpgme_error = _GPGERR(gpgme_error);
  1168     switch (gpgme_error) {
  1169     case GPG_ERR_NO_ERROR:
  1170         break;
  1171     case GPG_ERR_INV_VALUE:
  1172         assert(0);
  1173         return PEP_UNKNOWN_ERROR;
  1174     default:
  1175         return PEP_GET_KEY_FAILED;
  1176     };
  1177 
  1178 //    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1179 //    gpgme_error = _GPGERR(gpgme_error);
  1180 //    assert(gpgme_error != GPG_ERR_INV_VALUE);
  1181 
  1182 //    gpg.gpgme_op_keylist_end(session->ctx);
  1183 
  1184     return PEP_STATUS_OK;
  1185 }
  1186 
  1187 
  1188 static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
  1189     PEP_STATUS status = PEP_VERSION_MISMATCH;
  1190 
  1191     if (identity && identity->address) {    
  1192 #ifdef GPGME_VERSION_NUMBER 
  1193 #if (GPGME_VERSION_NUMBER >= 0x010700)
  1194         gpgme_error_t gpgme_error;
  1195         int userid_size = strlen(identity->address) + 1;
  1196         char* userid = (char*)(calloc(1, userid_size));
  1197         if (!userid)
  1198             return PEP_OUT_OF_MEMORY;
  1199         strlcpy(userid, identity->address, userid_size);
  1200         gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
  1201                                              0, 31536000, NULL, 
  1202                                              GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE);
  1203         gpgme_error = _GPGERR(gpgme_error);
  1204 
  1205         free(userid);
  1206 
  1207         if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
  1208             switch (gpgme_error) {
  1209                 case GPG_ERR_NO_ERROR:
  1210                     break;		    
  1211                 case GPG_ERR_INV_VALUE:
  1212                     return PEP_ILLEGAL_VALUE;
  1213                 case GPG_ERR_GENERAL:
  1214                     return PEP_CANNOT_CREATE_KEY;
  1215                 default:
  1216                     assert(0);
  1217                     return PEP_UNKNOWN_ERROR;
  1218             }        
  1219 
  1220             /* This is the same regardless of whether we got it from genkey or createkey */
  1221             gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1222             assert(gpgme_genkey_result);
  1223             assert(gpgme_genkey_result->fpr);
  1224 
  1225             char* fpr = strdup(gpgme_genkey_result->fpr);
  1226             gpgme_key_t key;
  1227             PEP_STATUS key_status = find_single_key(session, fpr, &key);
  1228             if (!key || key_status != PEP_STATUS_OK)
  1229                 return PEP_CANNOT_CREATE_KEY;
  1230                                 
  1231             gpgme_error = gpg.gpgme_op_createsubkey(session->ctx, key, 
  1232                                                     "RSA", 0, 
  1233                                                     31536000, GPGME_CREATE_NOPASSWD 
  1234                                                     | GPGME_CREATE_ENCR);
  1235 
  1236             switch (gpgme_error) {
  1237                 case GPG_ERR_NO_ERROR:
  1238                     break;		    
  1239                 case GPG_ERR_INV_VALUE:
  1240                     return PEP_ILLEGAL_VALUE;
  1241                 case GPG_ERR_GENERAL:
  1242                     return PEP_CANNOT_CREATE_KEY;
  1243                 default:
  1244                     assert(0);
  1245                     return PEP_UNKNOWN_ERROR;
  1246             }        
  1247             
  1248             free(identity->fpr);
  1249             identity->fpr = fpr;
  1250             if (identity->fpr == NULL)
  1251                 return PEP_OUT_OF_MEMORY;
  1252 
  1253 //            gpg.gpgme_key_unref(key);
  1254             
  1255             status = pgp_replace_only_uid(session, fpr,
  1256                         identity->username, identity->address);                       
  1257         }
  1258 #endif
  1259 #endif
  1260     }
  1261     
  1262     return status;
  1263 }
  1264 
  1265 PEP_STATUS pgp_generate_keypair(
  1266     PEP_SESSION session, pEp_identity *identity
  1267     )
  1268 {
  1269     assert(session);
  1270     assert(identity);
  1271     assert(identity->address);
  1272     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1273     assert(identity->username);
  1274 
  1275     PEP_STATUS status = _pgp_createkey(session, identity);
  1276     
  1277     if (status != PEP_VERSION_MISMATCH)
  1278         return status;
  1279         
  1280     gpgme_error_t gpgme_error;
  1281     char *parms;
  1282     const char *template =
  1283         "<GnupgKeyParms format=\"internal\">\n"
  1284         "Key-Type: RSA\n"
  1285         "Key-Length: 4096\n"
  1286         "Subkey-Type: RSA\n"
  1287         "Subkey-Length: 4096\n"
  1288         "Name-Real: %s\n"
  1289         "Name-Email: %s\n"
  1290         /* "Passphrase: %s\n" */
  1291         "Expire-Date: 1y\n"
  1292         "</GnupgKeyParms>\n";
  1293     int result;
  1294 
  1295     parms = calloc(1, PARMS_MAX);
  1296     assert(parms);
  1297     if (parms == NULL)
  1298         return PEP_OUT_OF_MEMORY;
  1299 
  1300     result = snprintf(parms, PARMS_MAX, template, identity->username,
  1301         identity->address); // , session->passphrase);
  1302     assert(result < PARMS_MAX);
  1303     if (result >= PARMS_MAX) {
  1304         free(parms);
  1305         return PEP_BUFFER_TOO_SMALL;
  1306     }
  1307    
  1308     // Versions not supporting create_keys also mess'up with callback on op_genkey 
  1309     gpgme_error = gpg.gpgme_set_passphrase_cb(session->ctx, NULL, NULL);
  1310     gpgme_error = _GPGERR(gpgme_error);
  1311     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1312 
  1313     gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
  1314     gpgme_error = _GPGERR(gpgme_error);
  1315     free(parms);
  1316 
  1317     switch (gpgme_error) {
  1318     case GPG_ERR_NO_ERROR:
  1319         break;
  1320     case GPG_ERR_INV_VALUE:
  1321         return PEP_ILLEGAL_VALUE;
  1322     case GPG_ERR_GENERAL:
  1323         return PEP_CANNOT_CREATE_KEY;
  1324     default:
  1325         assert(0);
  1326         return PEP_UNKNOWN_ERROR;
  1327     }
  1328 
  1329     gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1330     assert(gpgme_genkey_result);
  1331     assert(gpgme_genkey_result->fpr);
  1332 
  1333     // restore callback
  1334     gpgme_error = gpg.gpgme_set_passphrase_cb(session->ctx, passphrase_cb, NULL);
  1335     gpgme_error = _GPGERR(gpgme_error);
  1336     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1337 
  1338     free(identity->fpr);
  1339     identity->fpr = strdup(gpgme_genkey_result->fpr);
  1340     if (identity->fpr == NULL)
  1341         return PEP_OUT_OF_MEMORY;
  1342 
  1343     return PEP_STATUS_OK;
  1344 }
  1345 
  1346 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
  1347 {
  1348     gpgme_error_t gpgme_error;
  1349     gpgme_key_t key;
  1350 
  1351     assert(session);
  1352     assert(fpr);
  1353 
  1354     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1355     gpgme_error = _GPGERR(gpgme_error);
  1356     assert(gpgme_error != GPG_ERR_ENOMEM);
  1357     switch (gpgme_error) {
  1358     case GPG_ERR_NO_ERROR:
  1359         break;
  1360     case GPG_ERR_EOF:
  1361         return PEP_KEY_NOT_FOUND;
  1362     case GPG_ERR_INV_VALUE:
  1363         return PEP_ILLEGAL_VALUE;
  1364     case GPG_ERR_AMBIGUOUS_NAME:
  1365         return PEP_KEY_HAS_AMBIG_NAME;
  1366     case GPG_ERR_ENOMEM:
  1367         return PEP_OUT_OF_MEMORY;
  1368     default:
  1369         assert(0);
  1370         return PEP_UNKNOWN_ERROR;
  1371     }
  1372 
  1373     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1374     gpgme_error = _GPGERR(gpgme_error);
  1375     gpg.gpgme_key_unref(key);
  1376     switch (gpgme_error) {
  1377     case GPG_ERR_NO_ERROR:
  1378         break;
  1379     case GPG_ERR_INV_VALUE:
  1380         assert(0);
  1381         return PEP_UNKNOWN_ERROR;
  1382     case GPG_ERR_NO_PUBKEY:
  1383         assert(0);
  1384         return PEP_KEY_NOT_FOUND;
  1385     case GPG_ERR_AMBIGUOUS_NAME:
  1386         assert(0);
  1387         return PEP_KEY_HAS_AMBIG_NAME;
  1388     default:
  1389         assert(0);
  1390         return PEP_UNKNOWN_ERROR;
  1391     }
  1392 
  1393     return PEP_STATUS_OK;
  1394 }
  1395 
  1396 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1397                               size_t size, identity_list **private_idents)
  1398 {
  1399     gpgme_error_t gpgme_error;
  1400     gpgme_data_t dh;
  1401 
  1402     assert(session);
  1403     assert(key_data);
  1404 
  1405     if(private_idents)
  1406         *private_idents = NULL;
  1407 
  1408     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1409     gpgme_error = _GPGERR(gpgme_error);
  1410     assert(gpgme_error != GPG_ERR_ENOMEM);
  1411     switch (gpgme_error) {
  1412     case GPG_ERR_NO_ERROR:
  1413         break;
  1414     case GPG_ERR_ENOMEM:
  1415         return PEP_OUT_OF_MEMORY;
  1416     case GPG_ERR_INV_VALUE:
  1417         assert(0);
  1418         return PEP_UNKNOWN_ERROR;
  1419     default:
  1420         assert(0);
  1421         return PEP_UNKNOWN_ERROR;
  1422     }
  1423 
  1424     gpgme_import_result_t gpgme_import_result;
  1425 
  1426     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1427     gpgme_error = _GPGERR(gpgme_error);
  1428     switch (gpgme_error) {
  1429     case GPG_ERR_NO_ERROR:
  1430         if(private_idents)
  1431         {
  1432             gpgme_import_result =
  1433                 gpg.gpgme_op_import_result(session->ctx);
  1434             assert(gpgme_import_result);
  1435             if (!gpgme_import_result) {
  1436                 gpg.gpgme_data_release(dh);
  1437                 return PEP_UNKNOWN_ERROR;
  1438             }
  1439 
  1440             gpgme_import_status_t import;
  1441             for (import = gpgme_import_result->imports;
  1442                  import;
  1443                  import = import->next)
  1444              {
  1445                 if (import &&
  1446                     import->result == GPG_ERR_NO_ERROR &&
  1447                     import->status & GPGME_IMPORT_SECRET )
  1448                 {
  1449                     gpgme_key_t key = NULL;
  1450 
  1451                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1452                         import->fpr, &key, 0);
  1453                     gpgme_error = _GPGERR(gpgme_error);
  1454                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1455                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1456                         gpg.gpgme_data_release(dh);
  1457                         return PEP_OUT_OF_MEMORY;
  1458                     }
  1459 
  1460                     if (gpgme_error == GPG_ERR_NO_ERROR &&
  1461                         key && key->uids &&
  1462                         key->uids->email && key->uids->name)
  1463                     {
  1464                         pEp_identity *ident = new_identity(
  1465                              key->uids->email, import->fpr, NULL, key->uids->name);
  1466 
  1467                         gpg.gpgme_key_unref(key);
  1468 
  1469                         if (ident == NULL) {
  1470                             gpg.gpgme_data_release(dh);
  1471                             return PEP_OUT_OF_MEMORY;
  1472                         }
  1473 
  1474                         *private_idents = identity_list_add(*private_idents, ident);
  1475 
  1476                         if (*private_idents == NULL) {
  1477                             gpg.gpgme_data_release(dh);
  1478                             return PEP_OUT_OF_MEMORY;
  1479                         }
  1480                     }
  1481                     else
  1482                     {
  1483                         gpg.gpgme_key_unref(key);
  1484                         gpg.gpgme_data_release(dh);
  1485                         return PEP_UNKNOWN_ERROR;
  1486                     }
  1487                 }
  1488             }
  1489         }
  1490         break;
  1491     case GPG_ERR_INV_VALUE:
  1492         assert(0);
  1493         gpg.gpgme_data_release(dh);
  1494         return PEP_UNKNOWN_ERROR;
  1495     case GPG_ERR_NO_DATA:
  1496         gpg.gpgme_data_release(dh);
  1497         return PEP_ILLEGAL_VALUE;
  1498     default:
  1499         assert(0);
  1500         gpg.gpgme_data_release(dh);
  1501         return PEP_UNKNOWN_ERROR;
  1502     }
  1503 
  1504     gpg.gpgme_data_release(dh);
  1505     return PEP_STATUS_OK;
  1506 }
  1507 
  1508 PEP_STATUS pgp_export_keydata(
  1509         PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
  1510         bool secret
  1511     )
  1512 {
  1513     gpgme_error_t gpgme_error;
  1514     gpgme_data_t dh;
  1515     size_t _size;
  1516     char *buffer;
  1517     int reading;
  1518 
  1519     assert(session);
  1520     assert(fpr);
  1521     assert(key_data);
  1522     assert(size);
  1523 
  1524     gpgme_error = gpg.gpgme_data_new(&dh);
  1525     gpgme_error = _GPGERR(gpgme_error);
  1526     assert(gpgme_error != GPG_ERR_ENOMEM);
  1527     switch (gpgme_error) {
  1528     case GPG_ERR_NO_ERROR:
  1529         break;
  1530     case GPG_ERR_ENOMEM:
  1531         return PEP_OUT_OF_MEMORY;
  1532     case GPG_ERR_INV_VALUE:
  1533         assert(0);
  1534         return PEP_UNKNOWN_ERROR;
  1535     default:
  1536         assert(0);
  1537         return PEP_UNKNOWN_ERROR;
  1538     }
  1539 
  1540     if (secret)
  1541         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1542             GPGME_EXPORT_MODE_SECRET, dh);
  1543     else
  1544         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1545             GPGME_EXPORT_MODE_MINIMAL, dh);
  1546     gpgme_error = _GPGERR(gpgme_error);
  1547     switch (gpgme_error) {
  1548     case GPG_ERR_NO_ERROR:
  1549         break;
  1550     case GPG_ERR_EOF:
  1551         gpg.gpgme_data_release(dh);
  1552         return PEP_KEY_NOT_FOUND;
  1553     case GPG_ERR_INV_VALUE:
  1554         assert(0);
  1555         gpg.gpgme_data_release(dh);
  1556         return PEP_UNKNOWN_ERROR;
  1557     default:
  1558         assert(0);
  1559         gpg.gpgme_data_release(dh);
  1560         return PEP_UNKNOWN_ERROR;
  1561     };
  1562 
  1563     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1564     assert(_size != -1);
  1565     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1566 
  1567     buffer = malloc(_size + 1);
  1568     assert(buffer);
  1569     if (buffer == NULL) {
  1570         gpg.gpgme_data_release(dh);
  1571         return PEP_OUT_OF_MEMORY;
  1572     }
  1573 
  1574     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1575     assert(_size == reading);
  1576     if(_size != reading)
  1577         return PEP_CANNOT_EXPORT_KEY;
  1578 
  1579     // safeguard for the naive user
  1580     buffer[_size] = 0;
  1581 
  1582     *key_data = buffer;
  1583     *size = _size;
  1584 
  1585     gpg.gpgme_data_release(dh);
  1586     return PEP_STATUS_OK;
  1587 }
  1588 
  1589 PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
  1590                             stringpair_list_t** keyinfo_list)
  1591 {
  1592     gpgme_error_t gpgme_error;
  1593     assert(session);
  1594     assert(keyinfo_list);
  1595 
  1596     if (!session || !keyinfo_list)
  1597         return PEP_ILLEGAL_VALUE;
  1598 
  1599     *keyinfo_list = NULL;
  1600 
  1601     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1602     gpgme_error = _GPGERR(gpgme_error);
  1603 
  1604     switch(gpgme_error) {
  1605         case GPG_ERR_NO_ERROR:
  1606             break;
  1607         case GPG_ERR_INV_VALUE:
  1608             assert(0);
  1609             return PEP_UNKNOWN_ERROR;
  1610         default:
  1611             gpg.gpgme_op_keylist_end(session->ctx);
  1612             return PEP_GET_KEY_FAILED;
  1613     };
  1614 
  1615     gpgme_key_t key;
  1616     stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
  1617     stringpair_list_t* list_curr = _keyinfo_list;
  1618     stringpair_t* pair = NULL;
  1619 
  1620     do {
  1621         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1622         gpgme_error = _GPGERR(gpgme_error);
  1623 
  1624         switch(gpgme_error) {
  1625             case GPG_ERR_EOF:
  1626                 break;
  1627             case GPG_ERR_NO_ERROR:
  1628                 assert(key);
  1629                 assert(key->subkeys);
  1630                 if (!key || !key->subkeys)
  1631                     return PEP_GET_KEY_FAILED;
  1632 
  1633                 // first subkey is primary key
  1634                 char* fpr = key->subkeys->fpr;
  1635                 char* uid = key->uids->uid;
  1636 
  1637                 assert(fpr);
  1638                 assert(uid);
  1639                 if (!fpr)
  1640                     return PEP_GET_KEY_FAILED;
  1641 
  1642                 if (key->subkeys->revoked)
  1643                     continue;
  1644 
  1645                 pair = new_stringpair(fpr, uid);
  1646 
  1647                 assert(pair);
  1648 
  1649                 if (pair) {
  1650                     list_curr = stringpair_list_add(list_curr, pair);
  1651                     pair = NULL;
  1652 
  1653                     assert(list_curr);
  1654                     if (list_curr != NULL)
  1655                         break;
  1656                     else
  1657                         free_stringpair(pair);
  1658                 }
  1659                 // else fallthrough (list_curr or pair wasn't allocateable)
  1660             case GPG_ERR_ENOMEM:
  1661                 free_stringpair_list(_keyinfo_list);
  1662                 gpg.gpgme_op_keylist_end(session->ctx);
  1663                 return PEP_OUT_OF_MEMORY;
  1664             default:
  1665                 gpg.gpgme_op_keylist_end(session->ctx);
  1666                 return PEP_UNKNOWN_ERROR;
  1667         }
  1668     } while (gpgme_error != GPG_ERR_EOF);
  1669 
  1670     if (_keyinfo_list->value == NULL) {
  1671         free_stringpair_list(_keyinfo_list);
  1672         _keyinfo_list = NULL;
  1673     }
  1674 
  1675     *keyinfo_list = _keyinfo_list;
  1676 
  1677     return PEP_STATUS_OK;
  1678 }
  1679 
  1680 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1681     gpgme_keylist_mode_t add_mode)
  1682 {
  1683     gpgme_error_t gpgme_error;
  1684     gpgme_keylist_mode_t mode;
  1685 
  1686     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1687 
  1688     mode &= ~remove_mode;
  1689     mode |= add_mode;
  1690 
  1691     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1692     gpgme_error = _GPGERR(gpgme_error);
  1693     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1694 }
  1695 
  1696 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1697 {
  1698     gpgme_error_t gpgme_error;
  1699     gpgme_key_t key;
  1700 
  1701     assert(session);
  1702     assert(pattern);
  1703 
  1704     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1705 
  1706     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1707     gpgme_error = _GPGERR(gpgme_error);
  1708     switch (gpgme_error) {
  1709     case GPG_ERR_NO_ERROR:
  1710         break;
  1711     case GPG_ERR_INV_VALUE:
  1712         assert(0);
  1713         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1714         return PEP_UNKNOWN_ERROR;
  1715     default:
  1716         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1717         return PEP_GET_KEY_FAILED;
  1718     };
  1719 
  1720     gpgme_ctx_t import_ctx;
  1721     gpgme_error = gpg.gpgme_new(&import_ctx);
  1722     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1723 
  1724     do {
  1725         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1726         gpgme_error = _GPGERR(gpgme_error);
  1727         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1728         switch (gpgme_error) {
  1729         case GPG_ERR_EOF:
  1730             break;
  1731         case GPG_ERR_NO_ERROR:
  1732         {
  1733             gpgme_error_t gpgme_error;
  1734             gpgme_key_t keys[2];
  1735 
  1736             keys[0] = key;
  1737             keys[1] = NULL;
  1738 
  1739             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1740             gpgme_error = _GPGERR(gpgme_error);
  1741             gpg.gpgme_key_unref(key);
  1742             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1743             assert(gpgme_error != GPG_ERR_CONFLICT);
  1744         }
  1745             break;
  1746         case GPG_ERR_ENOMEM:
  1747             gpg.gpgme_op_keylist_end(session->ctx);
  1748             gpg.gpgme_release(import_ctx);
  1749             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1750             return PEP_OUT_OF_MEMORY;
  1751         default:
  1752             gpg.gpgme_op_keylist_end(session->ctx);
  1753             gpg.gpgme_release(import_ctx);
  1754             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1755             return PEP_UNKNOWN_ERROR;
  1756         };
  1757     } while (gpgme_error != GPG_ERR_EOF);
  1758 
  1759     gpg.gpgme_op_keylist_end(session->ctx);
  1760     gpg.gpgme_release(import_ctx);
  1761     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1762     return PEP_STATUS_OK;
  1763 }
  1764 
  1765 
  1766 static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
  1767                             stringlist_t** keylist,
  1768                             int private_only) {
  1769     gpgme_error_t gpgme_error;
  1770     gpgme_key_t key;
  1771 
  1772     assert(session);
  1773     assert(keylist);
  1774 
  1775     *keylist = NULL;
  1776 
  1777     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
  1778     gpgme_error = _GPGERR(gpgme_error);
  1779     switch (gpgme_error) {
  1780         case GPG_ERR_NO_ERROR:
  1781             break;
  1782         case GPG_ERR_INV_VALUE:
  1783             assert(0);
  1784             return PEP_UNKNOWN_ERROR;
  1785         default:
  1786             gpg.gpgme_op_keylist_end(session->ctx);
  1787             return PEP_GET_KEY_FAILED;
  1788     };
  1789 
  1790     stringlist_t *_keylist = new_stringlist(NULL);
  1791     stringlist_t *_k = _keylist;
  1792 
  1793     do {
  1794         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1795         gpgme_error = _GPGERR(gpgme_error);
  1796         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1797         switch (gpgme_error) {
  1798             case GPG_ERR_EOF:
  1799                 break;
  1800             case GPG_ERR_NO_ERROR:
  1801                 assert(key);
  1802                 assert(key->subkeys);
  1803                 if(!key->subkeys)
  1804                     break;
  1805                 assert(key->uids);
  1806                 gpgme_user_id_t kuid = key->uids;
  1807                 // check that at least one uid's email matches pattern exactly
  1808                 while(kuid) {
  1809                     if((pattern && kuid->email && strcmp(kuid->email, pattern) == 0) ||
  1810                        pattern == NULL /* match all */ )
  1811                     { 
  1812                         char *fpr = key->subkeys->fpr;
  1813                         assert(fpr);
  1814                         _k = stringlist_add(_k, fpr);
  1815                         assert(_k);
  1816                         if (_k == NULL){
  1817                             free_stringlist(_keylist);
  1818                             gpg.gpgme_op_keylist_end(session->ctx);
  1819                             return PEP_OUT_OF_MEMORY;
  1820                         }
  1821                         break;
  1822                     }
  1823                     kuid = kuid->next;
  1824                 }
  1825                 break;
  1826             case GPG_ERR_ENOMEM:
  1827                 free_stringlist(_keylist);
  1828                 gpg.gpgme_op_keylist_end(session->ctx);
  1829                 return PEP_OUT_OF_MEMORY;
  1830             default:
  1831                 gpg.gpgme_op_keylist_end(session->ctx);
  1832                 return PEP_UNKNOWN_ERROR;
  1833         };
  1834     } while (gpgme_error != GPG_ERR_EOF);
  1835 
  1836     gpg.gpgme_op_keylist_end(session->ctx);
  1837     if (_keylist->value == NULL) {
  1838         free_stringlist(_keylist);
  1839         _keylist = NULL;
  1840     }
  1841     *keylist = _keylist;
  1842     return PEP_STATUS_OK;
  1843 }
  1844 
  1845 PEP_STATUS pgp_find_keys(
  1846     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1847     )
  1848 {
  1849     return _pgp_search_keys(session, pattern, keylist, 0);
  1850 }
  1851 
  1852 PEP_STATUS pgp_find_private_keys(
  1853     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1854 )
  1855 {
  1856     return _pgp_search_keys(session, pattern, keylist, 1);
  1857 }
  1858 
  1859 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1860 {
  1861     gpgme_error_t gpgme_error;
  1862 
  1863     assert(session);
  1864     assert(pattern);
  1865 
  1866     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  1867         GPGME_EXPORT_MODE_EXTERN, NULL);
  1868     gpgme_error = _GPGERR(gpgme_error);
  1869     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1870     if (gpgme_error == GPG_ERR_NO_ERROR)
  1871         return PEP_STATUS_OK;
  1872     else
  1873         return PEP_CANNOT_SEND_KEY;
  1874 }
  1875 
  1876 PEP_STATUS pgp_get_key_rating(
  1877     PEP_SESSION session,
  1878     const char *fpr,
  1879     PEP_comm_type *comm_type
  1880     )
  1881 {
  1882     PEP_STATUS status = PEP_STATUS_OK;
  1883     gpgme_error_t gpgme_error;
  1884     gpgme_key_t key;
  1885 
  1886     assert(session);
  1887     assert(fpr);
  1888     assert(comm_type);
  1889 
  1890     *comm_type = PEP_ct_unknown;
  1891 
  1892     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1893     gpgme_error = _GPGERR(gpgme_error);
  1894     switch (gpgme_error) {
  1895     case GPG_ERR_NO_ERROR:
  1896         break;
  1897     case GPG_ERR_INV_VALUE:
  1898         assert(0);
  1899         return PEP_UNKNOWN_ERROR;
  1900     default:
  1901         return PEP_GET_KEY_FAILED;
  1902     };
  1903 
  1904     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1905     gpgme_error = _GPGERR(gpgme_error);
  1906     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1907 
  1908     if (key == NULL) {
  1909         gpg.gpgme_op_keylist_end(session->ctx);
  1910         return PEP_KEY_NOT_FOUND;
  1911     }
  1912 
  1913     switch (key->protocol) {
  1914     case GPGME_PROTOCOL_OpenPGP:
  1915     case GPGME_PROTOCOL_DEFAULT:
  1916         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1917         break;
  1918     case GPGME_PROTOCOL_CMS:
  1919         *comm_type = PEP_ct_CMS_unconfirmed;
  1920         break;
  1921     default:
  1922         *comm_type = PEP_ct_unknown;
  1923         gpg.gpgme_op_keylist_end(session->ctx);
  1924         return PEP_STATUS_OK;
  1925     }
  1926 
  1927     switch (gpgme_error) {
  1928     case GPG_ERR_EOF:
  1929         break;
  1930     case GPG_ERR_NO_ERROR:
  1931         assert(key);
  1932         assert(key->subkeys);
  1933         for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  1934             if (sk->length < 1024)
  1935                 *comm_type = PEP_ct_key_too_short;
  1936             else if (
  1937                 (
  1938                 (sk->pubkey_algo == GPGME_PK_RSA)
  1939                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  1940                 || (sk->pubkey_algo == GPGME_PK_RSA_S)
  1941                 )
  1942                 && sk->length == 1024
  1943                 )
  1944                 *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1945 
  1946             if (sk->invalid) {
  1947                 *comm_type = PEP_ct_key_b0rken;
  1948                 break;
  1949             }
  1950             if (sk->expired) {
  1951                 *comm_type = PEP_ct_key_expired;
  1952                 break;
  1953             }
  1954             if (sk->revoked) {
  1955                 *comm_type = PEP_ct_key_revoked;
  1956                 break;
  1957             }
  1958         }
  1959         break;
  1960     case GPG_ERR_ENOMEM:
  1961         gpg.gpgme_op_keylist_end(session->ctx);
  1962         *comm_type = PEP_ct_unknown;
  1963         return PEP_OUT_OF_MEMORY;
  1964     default:
  1965         gpg.gpgme_op_keylist_end(session->ctx);
  1966         return PEP_UNKNOWN_ERROR;
  1967     };
  1968 
  1969     gpg.gpgme_op_keylist_end(session->ctx);
  1970 
  1971     return status;
  1972 }
  1973 
  1974 
  1975 static ssize_t _nullwriter(
  1976         void *_handle,
  1977         const void *buffer,
  1978         size_t size
  1979     )
  1980 {
  1981     return size;
  1982 }
  1983 
  1984 typedef struct _replace_only_uid_state {
  1985     enum {
  1986         replace_uid_command = 0,
  1987         replace_uid_realname,
  1988         replace_uid_email,
  1989         replace_uid_comment,
  1990         replace_uid_adduid_ok,
  1991         replace_uid_select_for_delete,
  1992         replace_uid_delete,
  1993         replace_uid_delete_confirm,
  1994         replace_uid_select_for_trust,
  1995         replace_uid_trust,
  1996         replace_uid_trust_ultimate,
  1997         replace_uid_trust_ultimate_confirm,
  1998         replace_uid_quit,
  1999         replace_uid_save_okay,
  2000         replace_uid_exit,
  2001         replace_uid_error = -1
  2002     } state;
  2003 const char *realname;
  2004 const char *email;
  2005 } replace_only_uid_state;
  2006 
  2007 
  2008 static gpgme_error_t replace_only_uid_fsm(
  2009     void *_handle,
  2010     gpgme_status_code_t statuscode,
  2011     const char *args,
  2012     int fd
  2013 )
  2014 {
  2015     replace_only_uid_state *handle = _handle;
  2016         
  2017     switch (handle->state) {
  2018         case replace_uid_command:
  2019             if (statuscode == GPGME_STATUS_GET_LINE) {
  2020                 assert(strcmp(args, "keyedit.prompt") == 0);
  2021                 if (strcmp(args, "keyedit.prompt")) {
  2022                     handle->state = replace_uid_error;
  2023                     return GPG_ERR_GENERAL;
  2024                 }
  2025                 gpg.gpgme_io_write(fd, "adduid\n", 7);
  2026                 handle->state = replace_uid_realname;
  2027             }
  2028             break;
  2029             
  2030         case replace_uid_realname:
  2031             if (statuscode == GPGME_STATUS_GET_LINE) {
  2032                 assert(strcmp(args, "keygen.name") == 0);
  2033                 assert(handle->realname);
  2034                 if (strcmp(args, "keygen.name") || !handle->realname) {
  2035                     handle->state = replace_uid_error;
  2036                     return GPG_ERR_GENERAL;
  2037                 }
  2038                 size_t realname_strlen = strlen(handle->realname);
  2039                 char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
  2040                 if (!realname) {
  2041                     handle->state = replace_uid_error;
  2042                     return GPG_ERR_ENOMEM;
  2043                 }
  2044                 strlcpy(realname, handle->realname, realname_strlen + 1);
  2045                 realname[realname_strlen] = '\n'; 
  2046                 gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
  2047                 handle->state = replace_uid_email;
  2048                 free(realname);
  2049             }
  2050             break;
  2051             
  2052         case replace_uid_email:
  2053             if (statuscode == GPGME_STATUS_GET_LINE) {
  2054                 assert(strcmp(args, "keygen.email") == 0);
  2055                 assert(handle->email);
  2056                 if (strcmp(args, "keygen.email") || !handle->email) {
  2057                     handle->state = replace_uid_error;
  2058                     return GPG_ERR_GENERAL;
  2059                 }
  2060                 size_t email_strlen = strlen(handle->email);
  2061                 char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
  2062                 if (!email) {
  2063                     handle->state = replace_uid_error;
  2064                     return GPG_ERR_ENOMEM;
  2065                 }
  2066                 strlcpy(email, handle->email, email_strlen + 1);
  2067                 email[email_strlen] = '\n'; 
  2068                 gpg.gpgme_io_write(fd, email, email_strlen + 1);
  2069                 handle->state = replace_uid_comment;
  2070                 free(email);
  2071             }
  2072             break;
  2073 
  2074         case replace_uid_comment:
  2075             if (statuscode == GPGME_STATUS_GET_LINE) {
  2076                 assert(strcmp(args, "keygen.comment") == 0);
  2077                 if (strcmp(args, "keygen.comment") || !handle->email) {
  2078                     handle->state = replace_uid_error;
  2079                     return GPG_ERR_GENERAL;
  2080                 }
  2081                 gpg.gpgme_io_write(fd, "\n", 1);
  2082                 //handle->state = replace_uid_adduid_ok;
  2083                 handle->state = replace_uid_select_for_delete;
  2084             }
  2085             break;
  2086 /*
  2087         case replace_uid_adduid_ok:
  2088             if (statuscode == GPGME_STATUS_GET_LINE) {
  2089                 assert(strcmp(args, "keygen.userid.cmd") == 0);
  2090                 if (strcmp(args, "keygen.userid.cmd")) {
  2091                     handle->state = replace_uid_error;
  2092                     return GPG_ERR_GENERAL;
  2093                 }
  2094                 gpg.gpgme_io_write(fd, "O\n", 2);
  2095                 handle->state = replace_uid_select_for_delete;
  2096             }
  2097             break;
  2098 	    */
  2099 
  2100         case replace_uid_select_for_delete:
  2101             if (statuscode == GPGME_STATUS_GET_LINE) {
  2102                 assert(strcmp(args, "keyedit.prompt") == 0);
  2103                 if (strcmp(args, "keyedit.prompt")) {
  2104                     handle->state = replace_uid_error;
  2105                     return GPG_ERR_GENERAL;
  2106                 }
  2107                 gpg.gpgme_io_write(fd, "uid 1\n", 6);
  2108                 handle->state = replace_uid_delete;
  2109             }
  2110             break;
  2111 
  2112         case replace_uid_delete:
  2113             if (statuscode == GPGME_STATUS_GET_LINE) {
  2114                 assert(strcmp(args, "keyedit.prompt") == 0);
  2115                 if (strcmp(args, "keyedit.prompt")) {
  2116                     handle->state = replace_uid_error;
  2117                     return GPG_ERR_GENERAL;
  2118                 }
  2119                 gpg.gpgme_io_write(fd, "deluid\n", 7);
  2120                 handle->state = replace_uid_delete_confirm;
  2121             }
  2122             break;
  2123 
  2124         case replace_uid_delete_confirm:
  2125             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2126                 assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
  2127                 if (strcmp(args, "keyedit.remove.uid.okay")) {
  2128                     handle->state = replace_uid_error;
  2129                     return GPG_ERR_GENERAL;
  2130                 }
  2131                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2132                 handle->state = replace_uid_select_for_trust;
  2133             }
  2134             break;
  2135 
  2136         case replace_uid_select_for_trust:
  2137             if (statuscode == GPGME_STATUS_GET_LINE) {
  2138                 assert(strcmp(args, "keyedit.prompt") == 0);
  2139                 if (strcmp(args, "keyedit.prompt")) {
  2140                     handle->state = replace_uid_error;
  2141                     return GPG_ERR_GENERAL;
  2142                 }
  2143                 gpg.gpgme_io_write(fd, "uid 1\n", 6);
  2144                 handle->state = replace_uid_trust;
  2145             }
  2146             break;
  2147 
  2148         case replace_uid_trust:
  2149             if (statuscode == GPGME_STATUS_GET_LINE) {
  2150                 assert(strcmp(args, "keyedit.prompt") == 0);
  2151                 if (strcmp(args, "keyedit.prompt")) {
  2152                     handle->state = replace_uid_error;
  2153                     return GPG_ERR_GENERAL;
  2154                 }
  2155                 gpg.gpgme_io_write(fd, "trust\n", 6);
  2156                 handle->state = replace_uid_trust_ultimate;
  2157             }
  2158             break;
  2159 
  2160         case replace_uid_trust_ultimate:
  2161             if (statuscode == GPGME_STATUS_GET_LINE) {
  2162                 assert(strcmp(args, "edit_ownertrust.value") == 0);
  2163                 if (strcmp(args, "edit_ownertrust.value")) {
  2164                     handle->state = replace_uid_error;
  2165                     return GPG_ERR_GENERAL;
  2166                 }
  2167                 gpg.gpgme_io_write(fd, "5\n", 2);
  2168                 handle->state = replace_uid_trust_ultimate_confirm;
  2169             }
  2170             break;
  2171 
  2172         case replace_uid_trust_ultimate_confirm:
  2173             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2174                 assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
  2175                 if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
  2176                     handle->state = replace_uid_error;
  2177                     return GPG_ERR_GENERAL;
  2178                 }
  2179                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2180                 handle->state = replace_uid_quit;
  2181             }
  2182             break;
  2183 
  2184         case replace_uid_quit:
  2185             if (statuscode == GPGME_STATUS_GET_LINE) {
  2186                 assert(strcmp(args, "keyedit.prompt") == 0);
  2187                 if (strcmp(args, "keyedit.prompt")) {
  2188                     handle->state = replace_uid_error;
  2189                     return GPG_ERR_GENERAL;
  2190                 }
  2191                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2192                 handle->state = replace_uid_save_okay;
  2193             }
  2194             break;
  2195 
  2196         case replace_uid_save_okay:
  2197             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2198                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2199                 if (strcmp(args, "keyedit.save.okay")) {
  2200                     handle->state = replace_uid_error;
  2201                     return GPG_ERR_GENERAL;
  2202                 }
  2203                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2204                 handle->state = replace_uid_exit;
  2205             }
  2206             break;
  2207 
  2208         case replace_uid_exit:
  2209             break;
  2210 
  2211         case replace_uid_error:
  2212             return GPG_ERR_GENERAL;
  2213             
  2214         default:
  2215             break;                
  2216     }
  2217     return GPG_ERR_NO_ERROR;
  2218 }
  2219 
  2220 PEP_STATUS pgp_replace_only_uid(
  2221         PEP_SESSION session,
  2222         const char* fpr,
  2223         const char* realname,
  2224         const char* email
  2225     )
  2226 {
  2227     PEP_STATUS status = PEP_STATUS_OK;
  2228     gpgme_error_t gpgme_error;
  2229     gpgme_key_t key;
  2230     gpgme_data_t output;
  2231     replace_only_uid_state handle;
  2232 
  2233     assert(session);
  2234     assert(fpr);
  2235     assert(realname);
  2236     assert(email);
  2237     
  2238     memset(&handle, 0, sizeof(replace_only_uid_state));
  2239     handle.realname = realname;
  2240     handle.email = email;
  2241 
  2242     status = find_single_key(session, fpr, &key);
  2243     if (status != PEP_STATUS_OK)
  2244         return status;
  2245 
  2246     struct gpgme_data_cbs data_cbs;
  2247     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2248     data_cbs.write = _nullwriter;
  2249     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2250 
  2251     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, replace_only_uid_fsm, &handle,
  2252             output);
  2253     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2254     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2255         status = PEP_CANNOT_EDIT_KEY;
  2256     }
  2257 
  2258     gpg.gpgme_data_release(output);
  2259     gpg.gpgme_key_unref(key);
  2260 
  2261     return status;
  2262 }
  2263 
  2264 
  2265 typedef struct _renew_state {
  2266     enum {
  2267         renew_command = 0,
  2268         renew_date,
  2269         renew_secret_key,
  2270         renew_command2,
  2271         renew_date2,
  2272         renew_quit,
  2273         renew_save,
  2274         renew_exit,
  2275         renew_error = -1
  2276     } state;
  2277     const char *date_ref;
  2278 } renew_state;
  2279 
  2280 static gpgme_error_t renew_fsm(
  2281         void *_handle,
  2282         gpgme_status_code_t statuscode,
  2283         const char *args,
  2284         int fd
  2285     )
  2286 {
  2287     renew_state *handle = _handle;
  2288 
  2289     switch (handle->state) {
  2290         case renew_command:
  2291             if (statuscode == GPGME_STATUS_GET_LINE) {
  2292                 assert(strcmp(args, "keyedit.prompt") == 0);
  2293                 if (strcmp(args, "keyedit.prompt")) {
  2294                     handle->state = renew_error;
  2295                     return GPG_ERR_GENERAL;
  2296                 }
  2297                 gpg.gpgme_io_write(fd, "expire\n", 7);
  2298                 handle->state = renew_date;
  2299             }
  2300             break;
  2301 
  2302         case renew_date:
  2303             if (statuscode == GPGME_STATUS_GET_LINE) {
  2304                 assert(strcmp(args, "keygen.valid") == 0);
  2305                 if (strcmp(args, "keygen.valid")) {
  2306                     handle->state = renew_error;
  2307                     return GPG_ERR_GENERAL;
  2308                 }
  2309                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2310                 handle->state = renew_secret_key;
  2311             }
  2312             break;
  2313 
  2314         case renew_secret_key:
  2315             if (statuscode == GPGME_STATUS_GET_LINE) {
  2316                 assert(strcmp(args, "keyedit.prompt") == 0);
  2317                 if (strcmp(args, "keyedit.prompt")) {
  2318                     handle->state = renew_error;
  2319                     return GPG_ERR_GENERAL;
  2320                 }
  2321                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  2322                 handle->state = renew_command2;
  2323             }
  2324             break;
  2325 
  2326         case renew_command2:
  2327             if (statuscode == GPGME_STATUS_GET_LINE) {
  2328                 assert(strcmp(args, "keyedit.prompt") == 0);
  2329                 if (strcmp(args, "keyedit.prompt")) {
  2330                     handle->state = renew_error;
  2331                     return GPG_ERR_GENERAL;
  2332                 }
  2333                 gpg.gpgme_io_write(fd, "expire\n", 7);
  2334                 handle->state = renew_date2;
  2335             }
  2336             break;
  2337 
  2338         case renew_date2:
  2339             if (statuscode == GPGME_STATUS_GET_LINE) {
  2340                 assert(strcmp(args, "keygen.valid") == 0);
  2341                 if (strcmp(args, "keygen.valid")) {
  2342                     handle->state = renew_error;
  2343                     return GPG_ERR_GENERAL;
  2344                 }
  2345                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2346                 handle->state = renew_quit;
  2347             }
  2348             break;
  2349 
  2350         case renew_quit:
  2351             if (statuscode == GPGME_STATUS_GET_LINE) {
  2352                 assert(strcmp(args, "keyedit.prompt") == 0);
  2353                 if (strcmp(args, "keyedit.prompt")) {
  2354                     handle->state = renew_error;
  2355                     return GPG_ERR_GENERAL;
  2356                 }
  2357                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2358                 handle->state = renew_save;
  2359             }
  2360             break;
  2361 
  2362         case renew_save:
  2363             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2364                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2365                 if (strcmp(args, "keyedit.save.okay")) {
  2366                     handle->state = renew_error;
  2367                     return GPG_ERR_GENERAL;
  2368                 }
  2369                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2370                 handle->state = renew_exit;
  2371             }
  2372             break;
  2373 
  2374         case renew_exit:
  2375             break;
  2376 
  2377         case renew_error:
  2378             return GPG_ERR_GENERAL;
  2379     }
  2380 
  2381     return GPG_ERR_NO_ERROR;
  2382 }
  2383 
  2384 
  2385 PEP_STATUS pgp_renew_key(
  2386         PEP_SESSION session,
  2387         const char *fpr,
  2388         const timestamp *ts
  2389     )
  2390 {
  2391     PEP_STATUS status = PEP_STATUS_OK;
  2392     gpgme_error_t gpgme_error;
  2393     gpgme_key_t key;
  2394     gpgme_data_t output;
  2395     renew_state handle;
  2396     char date_text[12];
  2397 
  2398     assert(session);
  2399     assert(fpr);
  2400 
  2401     memset(&handle, 0, sizeof(renew_state));
  2402     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  2403             ts->tm_mon + 1, ts->tm_mday);
  2404     handle.date_ref = date_text;
  2405 
  2406     status = find_single_key(session, fpr, &key);
  2407     if (status != PEP_STATUS_OK)
  2408         return status;
  2409 
  2410     struct gpgme_data_cbs data_cbs;
  2411     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2412     data_cbs.write = _nullwriter;
  2413     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2414 
  2415     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  2416             output);
  2417     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2418     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2419         status = PEP_CANNOT_EDIT_KEY;
  2420     }
  2421 
  2422     gpg.gpgme_data_release(output);
  2423     gpg.gpgme_key_unref(key);
  2424 
  2425     return status;
  2426 }
  2427 
  2428 typedef struct _revoke_state {
  2429     enum {
  2430         revoke_command = 0,
  2431         revoke_approve,
  2432         revoke_reason_code,
  2433         revoke_reason_text,
  2434         revoke_reason_ok,
  2435         revoke_quit,
  2436         revoke_save,
  2437         revoke_exit,
  2438         revoke_error = -1
  2439     } state;
  2440     const char *reason_ref;
  2441 } revoke_state;
  2442 
  2443 
  2444 /*** unused?
  2445 static bool isemptystring(const char *str)
  2446 {
  2447     if (str == NULL)
  2448         return true;
  2449 
  2450     for (; str; str++) {
  2451         if (*str != ' ' && *str != '\t' && *str != '\n')
  2452             return false;
  2453     }
  2454 
  2455     return true;
  2456 }
  2457 ***/
  2458 
  2459 
  2460 static gpgme_error_t revoke_fsm(
  2461         void *_handle,
  2462         gpgme_status_code_t statuscode,
  2463         const char *args,
  2464         int fd
  2465     )
  2466 {
  2467     revoke_state *handle = _handle;
  2468 
  2469     switch (handle->state) {
  2470         case revoke_command:
  2471             if (statuscode == GPGME_STATUS_GET_LINE) {
  2472                 assert(strcmp(args, "keyedit.prompt") == 0);
  2473                 if (strcmp(args, "keyedit.prompt")) {
  2474                     handle->state = revoke_error;
  2475                     return GPG_ERR_GENERAL;
  2476                 }
  2477                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  2478                 handle->state = revoke_approve;
  2479             }
  2480             break;
  2481 
  2482         case revoke_approve:
  2483             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2484                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  2485                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  2486                     handle->state = revoke_error;
  2487                     return GPG_ERR_GENERAL;
  2488                 }
  2489                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2490                 handle->state = revoke_reason_code;
  2491             }
  2492             break;
  2493 
  2494         case revoke_reason_code:
  2495             if (statuscode == GPGME_STATUS_GET_LINE) {
  2496                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  2497                 if (strcmp(args, "ask_revocation_reason.code")) {
  2498                     handle->state = revoke_error;
  2499                     return GPG_ERR_GENERAL;
  2500                 }
  2501                 gpg.gpgme_io_write(fd, "1\n", 2);
  2502                 handle->state = revoke_reason_text;
  2503             }
  2504             break;
  2505 
  2506         case revoke_reason_text:
  2507             if (statuscode == GPGME_STATUS_GET_LINE) {
  2508                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  2509                 if (strcmp(args, "ask_revocation_reason.text")) {
  2510                     handle->state = revoke_error;
  2511                     return GPG_ERR_GENERAL;
  2512                 }
  2513                 // BUG: issues when reason given
  2514                 // Assertion failed: (gpg->cmd.code), function command_handler,
  2515                 // file engine-gpg.c, line 662.
  2516                 //
  2517                 // if (isemptystring(handle->reason_ref)) {
  2518                     gpg.gpgme_io_write(fd, "\n", 1);
  2519                 // }
  2520                 // else {
  2521                 //     size_t len = strlen(handle->reason_ref);
  2522                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  2523                 //     if (handle->reason_ref[len - 1] == '\n')
  2524                 //         gpg.gpgme_io_write(fd, "\n", 1);
  2525                 //     else
  2526                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  2527                 // }
  2528                 handle->state = revoke_reason_ok;
  2529             }
  2530             break;
  2531 
  2532         case revoke_reason_ok:
  2533             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2534                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  2535                 if (strcmp(args, "ask_revocation_reason.okay")) {
  2536                     handle->state = revoke_error;
  2537                     return GPG_ERR_GENERAL;
  2538                 }
  2539                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2540                 handle->state = revoke_quit;
  2541             }
  2542             break;
  2543 
  2544         case revoke_quit:
  2545             if (statuscode == GPGME_STATUS_GET_LINE) {
  2546                 assert(strcmp(args, "keyedit.prompt") == 0);
  2547                 if (strcmp(args, "keyedit.prompt")) {
  2548                     handle->state = revoke_error;
  2549                     return GPG_ERR_GENERAL;
  2550                 }
  2551                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2552                 handle->state = revoke_save;
  2553             }
  2554             break;
  2555 
  2556         case revoke_save:
  2557             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2558                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2559                 if (strcmp(args, "keyedit.save.okay")) {
  2560                     handle->state = revoke_error;
  2561                     return GPG_ERR_GENERAL;
  2562                 }
  2563                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2564                 handle->state = revoke_exit;
  2565             }
  2566             break;
  2567 
  2568         case revoke_exit:
  2569             break;
  2570 
  2571         case revoke_error:
  2572             return GPG_ERR_GENERAL;
  2573     }
  2574 
  2575     return GPG_ERR_NO_ERROR;
  2576 }
  2577 
  2578 PEP_STATUS pgp_revoke_key(
  2579         PEP_SESSION session,
  2580         const char *fpr,
  2581         const char *reason
  2582     )
  2583 {
  2584     PEP_STATUS status = PEP_STATUS_OK;
  2585     gpgme_error_t gpgme_error;
  2586     gpgme_key_t key;
  2587     gpgme_data_t output;
  2588     revoke_state handle;
  2589 
  2590     assert(session);
  2591     assert(fpr);
  2592 
  2593     memset(&handle, 0, sizeof(revoke_state));
  2594     handle.reason_ref = reason;
  2595 
  2596     status = find_single_key(session, fpr, &key);
  2597     if (status != PEP_STATUS_OK)
  2598         return status;
  2599 
  2600     struct gpgme_data_cbs data_cbs;
  2601     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2602     data_cbs.write = _nullwriter;
  2603     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2604 
  2605     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  2606             output);
  2607     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2608     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2609         status = PEP_CANNOT_EDIT_KEY;
  2610     }
  2611 
  2612     gpg.gpgme_data_release(output);
  2613     gpg.gpgme_key_unref(key);
  2614 
  2615     return status;
  2616 }
  2617 
  2618 PEP_STATUS pgp_key_expired(
  2619         PEP_SESSION session,
  2620         const char *fpr,
  2621         const time_t when,
  2622         bool *expired
  2623     )
  2624 {
  2625     PEP_STATUS status = PEP_STATUS_OK;
  2626     gpgme_key_t key;
  2627 
  2628     assert(session);
  2629     assert(fpr);
  2630     assert(expired);
  2631 
  2632     *expired = false;
  2633 
  2634     status = find_single_key(session, fpr, &key);
  2635     if (status != PEP_STATUS_OK)
  2636         return status;
  2637 
  2638     if ((key && key->expired) ||
  2639         (key && key->subkeys && key->subkeys->expired))
  2640     {
  2641         // Already marked expired
  2642         *expired = 1;
  2643     }
  2644     else if (key)
  2645     {
  2646         // Detect if will be expired
  2647         // i.e. Check that keys capabilities will
  2648         // not be expired at given time.
  2649         gpgme_subkey_t _sk;
  2650         bool crt_available = false;
  2651         bool sgn_available = false;
  2652         bool enc_available = false;
  2653         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  2654             if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
  2655                                                           // Also, zero means "does not expire"
  2656             {
  2657                 if (_sk->can_certify) crt_available = true;
  2658                 if (_sk->can_sign) sgn_available = true;
  2659                 if (_sk->can_encrypt) enc_available = true;
  2660                 // Authenticate is not used here.
  2661             }
  2662         }
  2663         if(!(crt_available && sgn_available && enc_available))
  2664         {
  2665             *expired = 1;
  2666         }
  2667     }
  2668     else
  2669     {
  2670         status = PEP_KEY_NOT_FOUND;
  2671     }
  2672 
  2673     gpg.gpgme_key_unref(key);
  2674     return status;
  2675 }
  2676 
  2677 PEP_STATUS pgp_key_revoked(
  2678         PEP_SESSION session,
  2679         const char *fpr,
  2680         bool *revoked
  2681     )
  2682 {
  2683     PEP_STATUS status = PEP_STATUS_OK;
  2684     gpgme_key_t key;
  2685 
  2686     assert(session);
  2687     assert(fpr);
  2688     assert(revoked);
  2689 
  2690     *revoked = false;
  2691 
  2692     status = find_single_key(session, fpr, &key);
  2693     if (status != PEP_STATUS_OK)
  2694         return status;
  2695 
  2696     if (key && key->subkeys)
  2697     {
  2698         *revoked = key->subkeys->revoked;
  2699     }
  2700     else
  2701     {
  2702         status = PEP_KEY_NOT_FOUND;
  2703     }
  2704 
  2705     gpg.gpgme_key_unref(key);
  2706     return status;
  2707 }
  2708 
  2709 PEP_STATUS pgp_key_created(
  2710         PEP_SESSION session,
  2711         const char *fpr,
  2712         time_t *created
  2713     )
  2714 {
  2715     PEP_STATUS status = PEP_STATUS_OK;
  2716     gpgme_key_t key;
  2717 
  2718     assert(session);
  2719     assert(fpr);
  2720     assert(created);
  2721 
  2722     *created = 0;
  2723 
  2724     status = find_single_key(session, fpr, &key);
  2725     if (status != PEP_STATUS_OK)
  2726         return status;
  2727 
  2728     if (key && key->subkeys)
  2729     {
  2730         *created = (time_t) key->subkeys->timestamp;
  2731     }
  2732     else
  2733     {
  2734         status = PEP_KEY_NOT_FOUND;
  2735     }
  2736 
  2737     gpg.gpgme_key_unref(key);
  2738     return status;
  2739 }
  2740 
  2741 PEP_STATUS pgp_binary(const char **path)
  2742 {
  2743     assert(path);
  2744     if (path == NULL)
  2745         return PEP_ILLEGAL_VALUE;
  2746 
  2747     *path = NULL;
  2748 
  2749     gpgme_engine_info_t info;
  2750     int err = gpg.gpgme_get_engine_info(&info);
  2751     assert(err == GPG_ERR_NO_ERROR);
  2752     if (err != GPG_ERR_NO_ERROR)
  2753         return PEP_OUT_OF_MEMORY;
  2754 
  2755     *path = info->file_name;
  2756 
  2757     return PEP_STATUS_OK;
  2758 }
  2759 
  2760 PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
  2761         bool *has_private) {
  2762     PEP_STATUS status = PEP_STATUS_OK;
  2763     gpgme_key_t output_key;
  2764     gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
  2765     *has_private = false;
  2766     switch (gpgerr) {
  2767         case GPG_ERR_EOF:
  2768         case GPG_ERR_INV_VALUE:
  2769             status = PEP_KEY_NOT_FOUND;
  2770             break;
  2771         case GPG_ERR_AMBIGUOUS_NAME:
  2772             status = PEP_KEY_HAS_AMBIG_NAME;
  2773             break;
  2774         case GPG_ERR_NO_ERROR:
  2775             *has_private = true;
  2776             gpg.gpgme_key_release(output_key);
  2777             break;
  2778         case GPG_ERR_ENOMEM:
  2779             status = PEP_OUT_OF_MEMORY;
  2780             break;
  2781         default:
  2782             status = PEP_UNKNOWN_ERROR;
  2783             break;
  2784     }
  2785     return status;
  2786 }