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