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