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