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