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