src/pgp_gpg.c
author Krista Bennett <krista@pep-project.org>
Thu, 23 Mar 2017 13:40:32 +0100
branchfdik_sync
changeset 1688 713d66e2a90f
parent 1675 369041ac3724
child 1689 0579d2132265
permissions -rw-r--r--
Periodic commit after reworking of beacon msg format - old code is still in there from previous step. Next step is to cull that and test.
     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_encrypt
   254             = (gpgme_op_encrypt_t) (intptr_t) dlsym(gpgme,
   255             "gpgme_op_encrypt");
   256         assert(gpg.gpgme_op_encrypt);
   257 
   258         gpg.gpgme_op_verify_result
   259             = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
   260             "gpgme_op_verify_result");
   261         assert(gpg.gpgme_op_verify_result);
   262 
   263         gpg.gpgme_signers_clear
   264             = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
   265             "gpgme_signers_clear");
   266         assert(gpg.gpgme_signers_clear);
   267 
   268         gpg.gpgme_signers_add
   269             = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
   270             "gpgme_signers_add");
   271         assert(gpg.gpgme_signers_add);
   272 
   273         gpg.gpgme_get_key
   274             = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
   275         assert(gpg.gpgme_get_key);
   276 
   277         gpg.gpgme_op_genkey
   278             = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
   279             "gpgme_op_genkey");
   280         assert(gpg.gpgme_op_genkey);
   281 
   282         gpg.gpgme_op_genkey_result
   283             = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
   284             "gpgme_op_genkey_result");
   285         assert(gpg.gpgme_op_genkey_result);
   286 
   287         gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
   288             dlsym(gpgme, "gpgme_op_delete");
   289         assert(gpg.gpgme_op_delete);
   290 
   291         gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
   292             dlsym(gpgme, "gpgme_op_import");
   293         assert(gpg.gpgme_op_import);
   294 
   295         gpg.gpgme_op_import_result
   296             = (gpgme_op_import_result_t) (intptr_t) dlsym(gpgme,
   297             "gpgme_op_import_result");
   298         assert(gpg.gpgme_op_import_result);
   299 
   300         gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
   301             dlsym(gpgme, "gpgme_op_export");
   302         assert(gpg.gpgme_op_export);
   303 
   304         gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
   305             dlsym(gpgme, "gpgme_set_keylist_mode");
   306         assert(gpg.gpgme_set_keylist_mode);
   307 
   308         gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
   309             dlsym(gpgme, "gpgme_get_keylist_mode");
   310         assert(gpg.gpgme_get_keylist_mode);
   311 
   312         gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
   313             dlsym(gpgme, "gpgme_op_keylist_start");
   314         assert(gpg.gpgme_op_keylist_start);
   315 
   316         gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
   317             dlsym(gpgme, "gpgme_op_keylist_next");
   318         assert(gpg.gpgme_op_keylist_next);
   319 
   320         gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
   321             dlsym(gpgme, "gpgme_op_keylist_end");
   322         assert(gpg.gpgme_op_keylist_end);
   323 
   324         gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
   325             dlsym(gpgme, "gpgme_op_import_keys");
   326         assert(gpg.gpgme_op_import_keys);
   327 
   328         gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
   329             dlsym(gpgme, "gpgme_key_ref");
   330         assert(gpg.gpgme_key_ref);
   331 
   332         gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
   333             dlsym(gpgme, "gpgme_key_unref");
   334         assert(gpg.gpgme_key_unref);
   335 
   336 		gpg.gpgme_key_release = (gpgme_key_release_t)(intptr_t)
   337 			dlsym(gpgme, "gpgme_key_release");
   338 		assert(gpg.gpgme_key_release);
   339 
   340         gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
   341             dlsym(gpgme, "gpgme_op_edit");
   342         assert(gpg.gpgme_op_edit);
   343 
   344         gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
   345             dlsym(gpgme, "gpgme_io_write");
   346         assert(gpg.gpgme_io_write);
   347 
   348         gpg.version = gpg.gpgme_check(NULL);
   349 
   350         const char * const cLocal = setlocale(LC_ALL, NULL);
   351         if (!cLocal || (strcmp(cLocal, "C") == 0))
   352             setlocale(LC_ALL, "");
   353 
   354         gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
   355 #ifdef LC_MESSAGES // Windoze
   356         gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
   357 #endif
   358     }
   359 
   360     gpg.gpgme_check(NULL);
   361     gpgme_error = gpg.gpgme_new(&session->ctx);
   362     gpgme_error = _GPGERR(gpgme_error);
   363     if (gpgme_error != GPG_ERR_NO_ERROR) {
   364         status = PEP_INIT_GPGME_INIT_FAILED;
   365         goto pep_error;
   366     }
   367     assert(session->ctx);
   368 
   369     gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
   370     gpgme_error = _GPGERR(gpgme_error);
   371     assert(gpgme_error == GPG_ERR_NO_ERROR);
   372 
   373     gpg.gpgme_set_armor(session->ctx, 1);
   374 
   375     return PEP_STATUS_OK;
   376 
   377 pep_error:
   378     pgp_release(session, in_first);
   379     return status;
   380 }
   381 
   382 void pgp_release(PEP_SESSION session, bool out_last)
   383 {
   384     if (session->ctx) {
   385         gpg.gpgme_release(session->ctx);
   386         session->ctx = NULL;
   387     }
   388 
   389     if (out_last)
   390         if (gpgme)
   391             dlclose(gpgme);
   392 }
   393 
   394 PEP_STATUS pgp_decrypt_and_verify(
   395     PEP_SESSION session, const char *ctext, size_t csize,
   396     const char *dsigtext, size_t dsigsize,
   397     char **ptext, size_t *psize, stringlist_t **keylist
   398     )
   399 {
   400     PEP_STATUS result;
   401     gpgme_error_t gpgme_error;
   402     gpgme_data_t cipher, plain;
   403     gpgme_data_type_t dt;
   404     gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
   405 
   406     stringlist_t *_keylist = NULL;
   407     //int i_key = 0;
   408 
   409     assert(session);
   410     assert(ctext);
   411     assert(csize);
   412     assert(ptext);
   413     assert(psize);
   414     assert(keylist);
   415 
   416     *ptext = NULL;
   417     *psize = 0;
   418     *keylist = NULL;
   419 
   420     gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
   421     gpgme_error = _GPGERR(gpgme_error);
   422     assert(gpgme_error == GPG_ERR_NO_ERROR);
   423     if (gpgme_error != GPG_ERR_NO_ERROR) {
   424         if (gpgme_error == GPG_ERR_ENOMEM)
   425             return PEP_OUT_OF_MEMORY;
   426         else
   427             return PEP_UNKNOWN_ERROR;
   428     }
   429 
   430     gpgme_error = gpg.gpgme_data_new(&plain);
   431     gpgme_error = _GPGERR(gpgme_error);
   432     assert(gpgme_error == GPG_ERR_NO_ERROR);
   433     if (gpgme_error != GPG_ERR_NO_ERROR) {
   434         gpg.gpgme_data_release(cipher);
   435         if (gpgme_error == GPG_ERR_ENOMEM)
   436             return PEP_OUT_OF_MEMORY;
   437         else
   438             return PEP_UNKNOWN_ERROR;
   439     }
   440 
   441 
   442     dt = gpg.gpgme_data_identify(cipher);
   443     switch (dt) {
   444 #if GPGME_VERSION_NUMBER > 0x010600
   445     case GPGME_DATA_TYPE_PGP_ENCRYPTED:
   446 #endif
   447     case GPGME_DATA_TYPE_PGP_SIGNED:
   448     case GPGME_DATA_TYPE_PGP_OTHER:
   449         if (dsigtext) {
   450             gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
   451         }
   452         else {
   453             gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
   454                 plain);
   455         }
   456         gpgme_error = _GPGERR(gpgme_error);
   457         assert(gpgme_error != GPG_ERR_INV_VALUE);
   458         assert(gpgme_error != GPG_ERR_NO_DATA);
   459 
   460         switch (gpgme_error) {
   461             case GPG_ERR_NO_ERROR:
   462             {
   463                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   464                 /* NOW is when we have to process the decrypt_result, period.
   465                    it is only valid until the next call on the context. */
   466                    
   467                 gpgme_key_t key;
   468                 memset(&key,0,sizeof(key));
   469                 stringlist_t* recipient_keylist = new_stringlist(NULL);
   470                 if (!recipient_keylist) {
   471                     gpg.gpgme_data_release(plain);
   472                     gpg.gpgme_data_release(cipher);
   473                     if (recipient_keylist)
   474                         free_stringlist(recipient_keylist);
   475                     return PEP_OUT_OF_MEMORY;
   476                 }
   477                
   478                 if (gpgme_decrypt_result != NULL) {
   479                     stringlist_t* _keylist = recipient_keylist;
   480                     for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   481                         // GPGME may give subkey's fpr instead of primary key's fpr.
   482                         // Therefore we ask for the primary fingerprint instead
   483                         // we assume that gpgme_get_key can find key by subkey's fpr
   484                         gpgme_error = gpg.gpgme_get_key(session->ctx,
   485                             r->keyid, &key, 0);
   486                         gpgme_error = _GPGERR(gpgme_error);
   487                         assert(gpgme_error != GPG_ERR_ENOMEM);
   488                         if (gpgme_error == GPG_ERR_ENOMEM) {
   489                             free_stringlist(_keylist);
   490                             result = PEP_OUT_OF_MEMORY;
   491                         }
   492                         // Primary key is given as the first subkey
   493                         if (gpgme_error == GPG_ERR_NO_ERROR &&
   494                             key && key->subkeys && key->subkeys->fpr
   495                             && key->subkeys->fpr[0]) {
   496                             _keylist = stringlist_add(_keylist, key->subkeys->fpr);
   497  
   498                             gpg.gpgme_key_unref(key);
   499  
   500                         }
   501                     }
   502                     assert(_keylist);
   503                     if (_keylist == NULL) {
   504                         free_stringlist(recipient_keylist);
   505                         if (*keylist)
   506                             free_stringlist(*keylist);
   507                         *keylist = NULL;
   508                         result = PEP_OUT_OF_MEMORY;
   509                     }
   510                 } /* Ok, so now we have any recipients it was encrypted for
   511                      in recipient_keylist */
   512             
   513                    
   514                 gpgme_verify_result_t gpgme_verify_result;
   515                 char *_buffer = NULL;
   516                 size_t reading;
   517                 size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
   518                 gpgme_signature_t gpgme_signature;
   519 
   520                 assert(length != -1);
   521                 gpg.gpgme_data_seek(plain, 0, SEEK_SET);
   522 
   523                 // TODO: make things less memory consuming
   524                 // the following algorithm allocates memory for the complete
   525                 // text
   526 
   527                 _buffer = malloc(length + 1);
   528                 assert(_buffer);
   529                 if (_buffer == NULL) {
   530                     gpg.gpgme_data_release(plain);
   531                     gpg.gpgme_data_release(cipher);
   532                     if (recipient_keylist)
   533                         free_stringlist(recipient_keylist);
   534                     return PEP_OUT_OF_MEMORY;
   535                 }
   536 
   537                 reading = gpg.gpgme_data_read(plain, _buffer, length);
   538                 assert(length == reading);
   539 
   540                 if (dsigtext) {  // Is this safe to do?
   541                     gpgme_data_t sigdata;
   542                     gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
   543                                                 dsigsize, 0);
   544                     gpg.gpgme_op_verify(session->ctx, sigdata, plain, NULL);
   545                     gpg.gpgme_data_release(sigdata);
   546                 }
   547 
   548                 gpgme_verify_result =
   549                     gpg.gpgme_op_verify_result(session->ctx);
   550                 assert(gpgme_verify_result);
   551                 gpgme_signature = gpgme_verify_result->signatures;
   552 
   553                 if (!gpgme_signature) {
   554                     // try cleartext sig verification
   555                     gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
   556                     gpgme_verify_result =
   557                         gpg.gpgme_op_verify_result(session->ctx);
   558                             assert(gpgme_verify_result);
   559                     gpgme_signature = gpgme_verify_result->signatures;                    
   560                 }
   561 
   562                 if (gpgme_signature) {
   563                     stringlist_t *k;
   564                     _keylist = new_stringlist(NULL);
   565                     assert(_keylist);
   566                     if (_keylist == NULL) {
   567                         gpg.gpgme_data_release(plain);
   568                         gpg.gpgme_data_release(cipher);
   569                         free(_buffer);
   570                         return PEP_OUT_OF_MEMORY;
   571                     }
   572                     k = _keylist;
   573 
   574                     result = PEP_DECRYPTED_AND_VERIFIED;
   575                     gpg.gpgme_check(NULL);
   576                     do { /* get all signers and put them at the front off
   577                             the keylist (likely only one) */
   578                         switch (_GPGERR(gpgme_signature->status)) {
   579                         case GPG_ERR_NO_ERROR:
   580                         {
   581                             // Some versions of gpg returns signer's
   582                             // signing subkey fingerprint instead of
   583                             // signer's primary key fingerprint.
   584                             // This is meant to get signer's primary
   585                             // key fingerprint, using subkey's.
   586 
   587                             gpgme_key_t key = NULL;
   588 
   589                             gpgme_error = gpg.gpgme_get_key(session->ctx,
   590                                 gpgme_signature->fpr, &key, 0);
   591                             gpgme_error = _GPGERR(gpgme_error);
   592                             assert(gpgme_error != GPG_ERR_ENOMEM);
   593                             if (gpgme_error == GPG_ERR_ENOMEM) {
   594                                 free_stringlist(_keylist);
   595                                 gpg.gpgme_data_release(plain);
   596                                 gpg.gpgme_data_release(cipher);
   597                                 free(_buffer);
   598                                 return PEP_OUT_OF_MEMORY;
   599                             }
   600                             // Primary key is given as the first subkey
   601                             if (gpgme_error == GPG_ERR_NO_ERROR &&
   602                                 key && key->subkeys && key->subkeys->fpr
   603                                 && key->subkeys->fpr[0])
   604                             {
   605                                 k = stringlist_add(k, key->subkeys->fpr);
   606 
   607                                 gpg.gpgme_key_unref(key);
   608 
   609                                 if (k == NULL) {
   610                                     free_stringlist(_keylist);
   611                                     if (recipient_keylist)
   612                                         free (recipient_keylist);
   613                                     gpg.gpgme_data_release(plain);
   614                                     gpg.gpgme_data_release(cipher);
   615                                     free(_buffer);
   616                                     return PEP_OUT_OF_MEMORY;
   617                                 }
   618                             }
   619                             else
   620                             {
   621                                 result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   622                                 break;
   623                             }
   624                             break;
   625                         }
   626                         case GPG_ERR_CERT_REVOKED:
   627                         case GPG_ERR_BAD_SIGNATURE:
   628                             result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   629                             break;
   630                         case GPG_ERR_SIG_EXPIRED:
   631                         case GPG_ERR_KEY_EXPIRED:
   632                         case GPG_ERR_NO_PUBKEY:
   633                             k = stringlist_add(k, gpgme_signature->fpr);
   634                             if (k == NULL) {
   635                                 free_stringlist(_keylist);
   636                                 if (recipient_keylist)
   637                                     free_stringlist(recipient_keylist);
   638                                 gpg.gpgme_data_release(plain);
   639                                 gpg.gpgme_data_release(cipher);
   640                                 free(_buffer);
   641                                 return PEP_OUT_OF_MEMORY;
   642                             }
   643                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   644                                 result = PEP_DECRYPTED;
   645                             break;
   646                         case GPG_ERR_GENERAL:
   647                             break;
   648                         default:
   649                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   650                                 result = PEP_DECRYPTED;
   651                             break;
   652                         }
   653                     } while ((gpgme_signature = gpgme_signature->next));
   654                 }
   655                 else {
   656                     result = PEP_DECRYPTED;
   657                 }
   658 
   659                 if (result == PEP_DECRYPTED_AND_VERIFIED
   660                     || result == PEP_DECRYPTED) {
   661                     *ptext = _buffer;
   662                     *psize = reading;
   663                     (*ptext)[*psize] = 0; // safeguard for naive users
   664                     *keylist = _keylist;
   665                     if (recipient_keylist)
   666                         if (!_keylist)
   667                             *keylist = new_stringlist(""); // no sig 
   668                         if (!(*keylist)) {
   669                             free_stringlist(_keylist);
   670                             if (recipient_keylist)
   671                                 free_stringlist(recipient_keylist);
   672                             gpg.gpgme_data_release(plain);
   673                             gpg.gpgme_data_release(cipher);
   674                             free(_buffer);
   675                             return PEP_OUT_OF_MEMORY;
   676                         }    
   677                         stringlist_append(*keylist, recipient_keylist);
   678                 }
   679                 else {
   680                     free_stringlist(_keylist);
   681                     if (recipient_keylist)
   682                         free_stringlist(recipient_keylist);
   683                     free(_buffer);
   684                 }
   685                 break;
   686             }
   687             case GPG_ERR_BAD_PASSPHRASE:
   688                 result = PEP_DECRYPT_NO_KEY;
   689                 break;
   690             case GPG_ERR_DECRYPT_FAILED:
   691             default:
   692             {
   693                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   694                 result = PEP_DECRYPT_NO_KEY;
   695 
   696                 if (gpgme_decrypt_result != NULL) {
   697                     if (gpgme_decrypt_result->unsupported_algorithm)
   698                         *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   699                     else
   700                         *keylist = new_stringlist("");
   701                     assert(*keylist);
   702                     if (*keylist == NULL) {
   703                         result = PEP_OUT_OF_MEMORY;
   704                         break;
   705                     }
   706                 }
   707             }
   708         }
   709         break;
   710 
   711     default:
   712         result = PEP_DECRYPT_WRONG_FORMAT;
   713     }
   714 
   715     gpg.gpgme_data_release(plain);
   716     gpg.gpgme_data_release(cipher);
   717     return result;
   718 }
   719 
   720 PEP_STATUS pgp_verify_text(
   721     PEP_SESSION session, const char *text, size_t size,
   722     const char *signature, size_t sig_size, stringlist_t **keylist
   723     )
   724 {
   725     PEP_STATUS result;
   726     gpgme_error_t gpgme_error;
   727     gpgme_data_t d_text, d_sig;
   728     stringlist_t *_keylist;
   729 
   730     assert(session);
   731     assert(text);
   732     assert(size);
   733     assert(signature);
   734     assert(sig_size);
   735     assert(keylist);
   736 
   737     *keylist = NULL;
   738 
   739     gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   740     gpgme_error = _GPGERR(gpgme_error);
   741     assert(gpgme_error == GPG_ERR_NO_ERROR);
   742     if (gpgme_error != GPG_ERR_NO_ERROR) {
   743         if (gpgme_error == GPG_ERR_ENOMEM)
   744             return PEP_OUT_OF_MEMORY;
   745         else
   746             return PEP_UNKNOWN_ERROR;
   747     }
   748 
   749     gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   750     gpgme_error = _GPGERR(gpgme_error);
   751     assert(gpgme_error == GPG_ERR_NO_ERROR);
   752     if (gpgme_error != GPG_ERR_NO_ERROR) {
   753         gpg.gpgme_data_release(d_text);
   754         if (gpgme_error == GPG_ERR_ENOMEM)
   755             return PEP_OUT_OF_MEMORY;
   756         else
   757             return PEP_UNKNOWN_ERROR;
   758     }
   759 
   760     gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
   761     gpgme_error = _GPGERR(gpgme_error);
   762     assert(gpgme_error != GPG_ERR_INV_VALUE);
   763 
   764     switch (gpgme_error) {
   765     case GPG_ERR_NO_ERROR:
   766     {
   767         gpgme_verify_result_t gpgme_verify_result;
   768         gpgme_signature_t gpgme_signature;
   769 
   770         gpgme_verify_result =
   771             gpg.gpgme_op_verify_result(session->ctx);
   772         assert(gpgme_verify_result);
   773         gpgme_signature = gpgme_verify_result->signatures;
   774 
   775         if (gpgme_signature) {
   776             stringlist_t *k;
   777             _keylist = new_stringlist(NULL);
   778             assert(_keylist);
   779             if (_keylist == NULL) {
   780                 gpg.gpgme_data_release(d_text);
   781                 gpg.gpgme_data_release(d_sig);
   782                 return PEP_OUT_OF_MEMORY;
   783             }
   784             k = _keylist;
   785 
   786             result = PEP_VERIFIED;
   787             do {
   788                 gpgme_key_t key;
   789                 memset(&key,0,sizeof(key));
   790 
   791                 // GPGME may give subkey's fpr instead of primary key's fpr.
   792                 // Therefore we ask for the primary fingerprint instead
   793                 // we assume that gpgme_get_key can find key by subkey's fpr
   794                 gpgme_error = gpg.gpgme_get_key(session->ctx,
   795                     gpgme_signature->fpr, &key, 0);
   796                 gpgme_error = _GPGERR(gpgme_error);
   797                 assert(gpgme_error != GPG_ERR_ENOMEM);
   798                 if (gpgme_error == GPG_ERR_ENOMEM) {
   799                     free_stringlist(_keylist);
   800                     gpg.gpgme_data_release(d_text);
   801                     gpg.gpgme_data_release(d_sig);
   802                     return PEP_OUT_OF_MEMORY;
   803                 }
   804                 // Primary key is given as the first subkey
   805                 if (gpgme_error == GPG_ERR_NO_ERROR &&
   806                     key && key->subkeys && key->subkeys->fpr
   807                     && key->subkeys->fpr[0])
   808                 {
   809                     k = stringlist_add(k, key->subkeys->fpr);
   810 
   811                     gpg.gpgme_key_unref(key);
   812 
   813                     if (k == NULL) {
   814                         free_stringlist(_keylist);
   815                         gpg.gpgme_data_release(d_text);
   816                         gpg.gpgme_data_release(d_sig);
   817                         return PEP_OUT_OF_MEMORY;
   818                     }
   819                 }
   820                 else {
   821                     result = PEP_VERIFY_SIGNATURE_DOES_NOT_MATCH;
   822                     break;
   823                 }
   824 
   825                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   826                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   827                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   828                         if (result == PEP_VERIFIED
   829                             || result == PEP_VERIFIED_AND_TRUSTED)
   830                             result = PEP_UNENCRYPTED; // ?? What should this be changed to?
   831                     }
   832                     else {
   833                         result = PEP_VERIFY_SIGNATURE_DOES_NOT_MATCH;
   834                         break;
   835                     }
   836                 }
   837                 else {
   838                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   839                         if (result == PEP_VERIFIED)
   840                             result = PEP_VERIFIED_AND_TRUSTED;
   841                     }
   842                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   843                         // good
   844                     }
   845                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   846                         result = PEP_VERIFY_NO_KEY;
   847                     }
   848                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   849                         if (result == PEP_VERIFIED
   850                             || result == PEP_VERIFIED_AND_TRUSTED)
   851                             result = PEP_UNENCRYPTED;
   852                     }
   853                     else {
   854                         // do nothing
   855                     }
   856                 }
   857             } while ((gpgme_signature = gpgme_signature->next));
   858             *keylist = _keylist;
   859         }
   860         else {
   861             result = PEP_UNENCRYPTED;
   862         }
   863         break;
   864     }
   865         break;
   866     case GPG_ERR_NO_DATA:
   867         result = PEP_DECRYPT_WRONG_FORMAT;
   868         break;
   869     case GPG_ERR_INV_VALUE:
   870     default:
   871         result = PEP_UNKNOWN_ERROR;
   872         break;
   873     }
   874 
   875     gpg.gpgme_data_release(d_text);
   876     gpg.gpgme_data_release(d_sig);
   877 
   878     return result;
   879 }
   880 
   881 
   882 static PEP_STATUS pgp_encrypt_sign_optional(    
   883     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   884     size_t psize, char **ctext, size_t *csize, bool sign
   885 )
   886 {    
   887     PEP_STATUS result;
   888     gpgme_error_t gpgme_error;
   889     gpgme_data_t plain, cipher;
   890     gpgme_key_t *rcpt;
   891     gpgme_encrypt_flags_t flags;
   892     const stringlist_t *_keylist;
   893     int i, j;
   894 
   895     assert(session);
   896     assert(keylist);
   897     assert(ptext);
   898     assert(psize);
   899     assert(ctext);
   900     assert(csize);
   901 
   902     *ctext = NULL;
   903     *csize = 0;
   904 
   905     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
   906     gpgme_error = _GPGERR(gpgme_error);
   907     assert(gpgme_error == GPG_ERR_NO_ERROR);
   908     if (gpgme_error != GPG_ERR_NO_ERROR) {
   909         if (gpgme_error == GPG_ERR_ENOMEM)
   910             return PEP_OUT_OF_MEMORY;
   911         else
   912             return PEP_UNKNOWN_ERROR;
   913     }
   914 
   915     gpgme_error = gpg.gpgme_data_new(&cipher);
   916     gpgme_error = _GPGERR(gpgme_error);
   917     assert(gpgme_error == GPG_ERR_NO_ERROR);
   918     if (gpgme_error != GPG_ERR_NO_ERROR) {
   919         gpg.gpgme_data_release(plain);
   920         if (gpgme_error == GPG_ERR_ENOMEM)
   921             return PEP_OUT_OF_MEMORY;
   922         else
   923             return PEP_UNKNOWN_ERROR;
   924     }
   925 
   926     rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
   927     assert(rcpt);
   928     if (rcpt == NULL) {
   929         gpg.gpgme_data_release(plain);
   930         gpg.gpgme_data_release(cipher);
   931         return PEP_OUT_OF_MEMORY;
   932     }
   933 
   934     gpg.gpgme_signers_clear(session->ctx);
   935 
   936     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
   937         assert(_keylist->value);
   938         gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
   939             &rcpt[i], 0);
   940         gpgme_error = _GPGERR(gpgme_error);
   941         assert(gpgme_error != GPG_ERR_ENOMEM);
   942 
   943         switch (gpgme_error) {
   944         case GPG_ERR_ENOMEM:
   945             for (j = 0; j<i; j++)
   946                 gpg.gpgme_key_unref(rcpt[j]);
   947             free(rcpt);
   948             gpg.gpgme_data_release(plain);
   949             gpg.gpgme_data_release(cipher);
   950             return PEP_OUT_OF_MEMORY;
   951         case GPG_ERR_NO_ERROR:
   952             if (i == 0 && sign) {
   953                 gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
   954                 _gpgme_error = _GPGERR(_gpgme_error);
   955                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
   956             }
   957             break;
   958         case GPG_ERR_EOF:
   959             for (j = 0; j<i; j++)
   960                 gpg.gpgme_key_unref(rcpt[j]);
   961             free(rcpt);
   962             gpg.gpgme_data_release(plain);
   963             gpg.gpgme_data_release(cipher);
   964             return PEP_KEY_NOT_FOUND;
   965         case GPG_ERR_AMBIGUOUS_NAME:
   966             for (j = 0; j<i; j++)
   967                 gpg.gpgme_key_unref(rcpt[j]);
   968             free(rcpt);
   969             gpg.gpgme_data_release(plain);
   970             gpg.gpgme_data_release(cipher);
   971             return PEP_KEY_HAS_AMBIG_NAME;
   972         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
   973             // FPR is not a fingerprint or key ID
   974             for (j = 0; j<i; j++)
   975                 gpg.gpgme_key_unref(rcpt[j]);
   976             free(rcpt);
   977             gpg.gpgme_data_release(plain);
   978             gpg.gpgme_data_release(cipher);
   979             return PEP_GET_KEY_FAILED;
   980         }
   981     }
   982 
   983     // TODO: remove that and replace with proper key management
   984     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
   985     
   986     if (sign) {
   987         gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
   988             plain, cipher);
   989     }
   990     else {
   991         gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
   992             plain, cipher);
   993     }
   994     
   995     gpgme_error = _GPGERR(gpgme_error);
   996     switch (gpgme_error) {
   997     case GPG_ERR_NO_ERROR:
   998     {
   999         char *_buffer = NULL;
  1000         size_t reading;
  1001         size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
  1002         assert(length != -1);
  1003         gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
  1004 
  1005         // TODO: make things less memory consuming
  1006         // the following algorithm allocates a buffer for the complete text
  1007 
  1008         _buffer = malloc(length + 1);
  1009         assert(_buffer);
  1010         if (_buffer == NULL) {
  1011             for (j = 0; j<stringlist_length(keylist); j++)
  1012                 gpg.gpgme_key_unref(rcpt[j]);
  1013             free(rcpt);
  1014             gpg.gpgme_data_release(plain);
  1015             gpg.gpgme_data_release(cipher);
  1016             return PEP_OUT_OF_MEMORY;
  1017         }
  1018 
  1019         reading = gpg.gpgme_data_read(cipher, _buffer, length);
  1020         assert(length == reading);
  1021 
  1022         *ctext = _buffer;
  1023         *csize = reading;
  1024         (*ctext)[*csize] = 0; // safeguard for naive users
  1025         result = PEP_STATUS_OK;
  1026         break;
  1027     }
  1028     default:
  1029         result = PEP_UNKNOWN_ERROR;
  1030     }
  1031 
  1032     for (j = 0; j<stringlist_length(keylist); j++)
  1033         gpg.gpgme_key_unref(rcpt[j]);
  1034     free(rcpt);
  1035     gpg.gpgme_data_release(plain);
  1036     gpg.gpgme_data_release(cipher);
  1037     return result;
  1038 }
  1039 
  1040 PEP_STATUS pgp_encrypt_only(
  1041     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1042     size_t psize, char **ctext, size_t *csize
  1043     )
  1044 {
  1045     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1046         psize, ctext, csize, false);
  1047 }
  1048 
  1049 PEP_STATUS pgp_encrypt_and_sign(
  1050     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1051     size_t psize, char **ctext, size_t *csize
  1052     )
  1053 {
  1054     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1055         psize, ctext, csize, true);
  1056 }
  1057 
  1058 PEP_STATUS pgp_sign_text(
  1059     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1060     size_t psize, char **stext, size_t *ssize
  1061     )
  1062 {
  1063     PEP_STATUS result;
  1064     gpgme_error_t gpgme_error;
  1065     gpgme_data_t plain, detached_sig;
  1066     gpgme_key_t *rcpt;
  1067     gpgme_sig_mode_t GPGME_SIG_MODE_DETACH;
  1068     const stringlist_t *_keylist;
  1069     int i, j;
  1070 
  1071     assert(session);
  1072     assert(keylist);
  1073     assert(ptext);
  1074     assert(psize);
  1075     assert(stext);
  1076     assert(ssize);
  1077 
  1078     *stext = NULL;
  1079     *ssize = 0;
  1080 
  1081     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
  1082     gpgme_error = _GPGERR(gpgme_error);
  1083     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1084     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1085         if (gpgme_error == GPG_ERR_ENOMEM)
  1086             return PEP_OUT_OF_MEMORY;
  1087         else
  1088             return PEP_UNKNOWN_ERROR;
  1089     }
  1090 
  1091     gpgme_error = gpg.gpgme_data_new(&detached_sig);
  1092     gpgme_error = _GPGERR(gpgme_error);
  1093     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1094     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1095         gpg.gpgme_data_release(plain);
  1096         if (gpgme_error == GPG_ERR_ENOMEM)
  1097             return PEP_OUT_OF_MEMORY;
  1098         else
  1099             return PEP_UNKNOWN_ERROR;
  1100     }
  1101 
  1102     /* FIXME: Why +1? */
  1103     rcpt = calloc(2, sizeof(gpgme_key_t));
  1104     assert(rcpt);
  1105     if (rcpt == NULL) {
  1106         gpg.gpgme_data_release(plain);
  1107         gpg.gpgme_data_release(detached_sig);
  1108         return PEP_OUT_OF_MEMORY;
  1109     }
  1110 
  1111     gpg.gpgme_signers_clear(session->ctx);
  1112 
  1113     assert(keylist->value);
  1114     if (!keylist->value)
  1115         return PEP_KEY_NOT_FOUND;
  1116         
  1117     gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
  1118         &rcpt[0], 0);
  1119         
  1120     gpgme_error = _GPGERR(gpgme_error);
  1121     assert(gpgme_error != GPG_ERR_ENOMEM);
  1122 
  1123     switch (gpgme_error) {
  1124         case GPG_ERR_ENOMEM:
  1125             gpg.gpgme_key_unref(rcpt[0]);
  1126             free(rcpt);
  1127             gpg.gpgme_data_release(plain);
  1128             gpg.gpgme_data_release(detached_sig);
  1129             return PEP_OUT_OF_MEMORY;
  1130         case GPG_ERR_NO_ERROR:
  1131             gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
  1132             gpgme_error = _GPGERR(gpgme_error);
  1133             assert(gpgme_error == GPG_ERR_NO_ERROR);
  1134             break;
  1135         case GPG_ERR_EOF:
  1136             gpg.gpgme_key_unref(rcpt[0]);
  1137             free(rcpt);
  1138             gpg.gpgme_data_release(plain);
  1139             gpg.gpgme_data_release(detached_sig);
  1140             return PEP_KEY_NOT_FOUND;
  1141         case GPG_ERR_AMBIGUOUS_NAME:
  1142             gpg.gpgme_key_unref(rcpt[0]);
  1143             free(rcpt);
  1144             gpg.gpgme_data_release(plain);
  1145             gpg.gpgme_data_release(detached_sig);
  1146             return PEP_KEY_HAS_AMBIG_NAME;
  1147         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
  1148             // FPR is not a fingerprint or key ID
  1149             gpg.gpgme_key_unref(rcpt[0]);
  1150             free(rcpt);
  1151             gpg.gpgme_data_release(plain);
  1152             gpg.gpgme_data_release(detached_sig);
  1153             return PEP_GET_KEY_FAILED;
  1154     }
  1155 
  1156     sig_mode = GPGME_SIG_MODE_NORMAL;
  1157     
  1158     gpgme_error = gpg.gpgme_op_sign(session->ctx, plain, detached_sig, sig_mode);
  1159     
  1160     gpgme_error = _GPGERR(gpgme_error);
  1161     switch (gpgme_error) {
  1162     case GPG_ERR_NO_ERROR:
  1163     {
  1164         char *_buffer = NULL;
  1165         size_t reading;
  1166         size_t length = gpg.gpgme_data_seek(detached_sig, 0, SEEK_END);
  1167         assert(length != -1);
  1168         gpg.gpgme_data_seek(detached_sig, 0, SEEK_SET);
  1169 
  1170         // TODO: make things less memory consuming
  1171         // the following algorithm allocates a buffer for the complete text
  1172 
  1173         _buffer = malloc(length + 1);
  1174         assert(_buffer);
  1175         if (_buffer == NULL) {
  1176             for (j = 0; j<stringlist_length(keylist); j++)
  1177                 gpg.gpgme_key_unref(rcpt[j]);
  1178             free(rcpt);
  1179             gpg.gpgme_data_release(plain);
  1180             gpg.gpgme_data_release(detached_sig);
  1181             return PEP_OUT_OF_MEMORY;
  1182         }
  1183 
  1184         reading = gpg.gpgme_data_read(detached_sig, _buffer, length);
  1185         assert(length == reading);
  1186 
  1187         *stext = _buffer;
  1188         *ssize = reading;
  1189         (*stext)[*ssize] = 0; // safeguard for naive users
  1190         result = PEP_STATUS_OK;
  1191         break;
  1192     }
  1193     default:
  1194         result = PEP_UNKNOWN_ERROR;
  1195     }
  1196 
  1197     gpg.gpgme_key_unref(rcpt[0]);
  1198     free(rcpt);
  1199     gpg.gpgme_data_release(plain);
  1200     gpg.gpgme_data_release(detached_sig);
  1201     return result;
  1202 }
  1203 
  1204 PEP_STATUS pgp_generate_keypair(
  1205     PEP_SESSION session, pEp_identity *identity
  1206     )
  1207 {
  1208     gpgme_error_t gpgme_error;
  1209     char *parms;
  1210     const char *template =
  1211         "<GnupgKeyParms format=\"internal\">\n"
  1212         "Key-Type: RSA\n"
  1213         "Key-Length: 4096\n"
  1214         "Subkey-Type: RSA\n"
  1215         "Subkey-Length: 4096\n"
  1216         "Name-Real: %s\n"
  1217         "Name-Email: %s\n"
  1218         /* "Passphrase: %s\n" */
  1219         "Expire-Date: 1y\n"
  1220         "</GnupgKeyParms>\n";
  1221     int result;
  1222     gpgme_genkey_result_t gpgme_genkey_result;
  1223 
  1224     assert(session);
  1225     assert(identity);
  1226     assert(identity->address);
  1227     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1228     assert(identity->username);
  1229 
  1230     parms = calloc(1, PARMS_MAX);
  1231     assert(parms);
  1232     if (parms == NULL)
  1233         return PEP_OUT_OF_MEMORY;
  1234 
  1235     result = snprintf(parms, PARMS_MAX, template, identity->username,
  1236         identity->address); // , session->passphrase);
  1237     assert(result < PARMS_MAX);
  1238     if (result >= PARMS_MAX) {
  1239         free(parms);
  1240         return PEP_BUFFER_TOO_SMALL;
  1241     }
  1242 
  1243     gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
  1244     gpgme_error = _GPGERR(gpgme_error);
  1245     free(parms);
  1246 
  1247     switch (gpgme_error) {
  1248     case GPG_ERR_NO_ERROR:
  1249         break;
  1250     case GPG_ERR_INV_VALUE:
  1251         return PEP_ILLEGAL_VALUE;
  1252     case GPG_ERR_GENERAL:
  1253         return PEP_CANNOT_CREATE_KEY;
  1254     default:
  1255         assert(0);
  1256         return PEP_UNKNOWN_ERROR;
  1257     }
  1258 
  1259     gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1260     assert(gpgme_genkey_result);
  1261     assert(gpgme_genkey_result->fpr);
  1262 
  1263     free(identity->fpr);
  1264     identity->fpr = strdup(gpgme_genkey_result->fpr);
  1265     if (identity->fpr == NULL)
  1266         return PEP_OUT_OF_MEMORY;
  1267 
  1268     return PEP_STATUS_OK;
  1269 }
  1270 
  1271 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
  1272 {
  1273     gpgme_error_t gpgme_error;
  1274     gpgme_key_t key;
  1275 
  1276     assert(session);
  1277     assert(fpr);
  1278 
  1279     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1280     gpgme_error = _GPGERR(gpgme_error);
  1281     assert(gpgme_error != GPG_ERR_ENOMEM);
  1282     switch (gpgme_error) {
  1283     case GPG_ERR_NO_ERROR:
  1284         break;
  1285     case GPG_ERR_EOF:
  1286         return PEP_KEY_NOT_FOUND;
  1287     case GPG_ERR_INV_VALUE:
  1288         return PEP_ILLEGAL_VALUE;
  1289     case GPG_ERR_AMBIGUOUS_NAME:
  1290         return PEP_KEY_HAS_AMBIG_NAME;
  1291     case GPG_ERR_ENOMEM:
  1292         return PEP_OUT_OF_MEMORY;
  1293     default:
  1294         assert(0);
  1295         return PEP_UNKNOWN_ERROR;
  1296     }
  1297 
  1298     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1299     gpgme_error = _GPGERR(gpgme_error);
  1300     gpg.gpgme_key_unref(key);
  1301     switch (gpgme_error) {
  1302     case GPG_ERR_NO_ERROR:
  1303         break;
  1304     case GPG_ERR_INV_VALUE:
  1305         assert(0);
  1306         return PEP_UNKNOWN_ERROR;
  1307     case GPG_ERR_NO_PUBKEY:
  1308         assert(0);
  1309         return PEP_KEY_NOT_FOUND;
  1310     case GPG_ERR_AMBIGUOUS_NAME:
  1311         assert(0);
  1312         return PEP_KEY_HAS_AMBIG_NAME;
  1313     default:
  1314         assert(0);
  1315         return PEP_UNKNOWN_ERROR;
  1316     }
  1317 
  1318     return PEP_STATUS_OK;
  1319 }
  1320 
  1321 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1322                               size_t size, identity_list **private_idents)
  1323 {
  1324     gpgme_error_t gpgme_error;
  1325     gpgme_data_t dh;
  1326 
  1327     assert(session);
  1328     assert(key_data);
  1329 
  1330     if(private_idents)
  1331         *private_idents = NULL;
  1332 
  1333     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1334     gpgme_error = _GPGERR(gpgme_error);
  1335     assert(gpgme_error != GPG_ERR_ENOMEM);
  1336     switch (gpgme_error) {
  1337     case GPG_ERR_NO_ERROR:
  1338         break;
  1339     case GPG_ERR_ENOMEM:
  1340         return PEP_OUT_OF_MEMORY;
  1341     case GPG_ERR_INV_VALUE:
  1342         assert(0);
  1343         return PEP_UNKNOWN_ERROR;
  1344     default:
  1345         assert(0);
  1346         return PEP_UNKNOWN_ERROR;
  1347     }
  1348 
  1349     gpgme_import_result_t gpgme_import_result;
  1350 
  1351     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1352     gpgme_error = _GPGERR(gpgme_error);
  1353     switch (gpgme_error) {
  1354     case GPG_ERR_NO_ERROR:
  1355         if(private_idents)
  1356         {
  1357             gpgme_import_result =
  1358                 gpg.gpgme_op_import_result(session->ctx);
  1359             assert(gpgme_import_result);
  1360             if (!gpgme_import_result) {
  1361                 gpg.gpgme_data_release(dh);
  1362                 return PEP_UNKNOWN_ERROR;
  1363             }
  1364 
  1365             gpgme_import_status_t import;
  1366             for (import = gpgme_import_result->imports;
  1367                  import;
  1368                  import = import->next)
  1369              {
  1370                 if (import &&
  1371                     import->result == GPG_ERR_NO_ERROR &&
  1372                     import->status & GPGME_IMPORT_SECRET )
  1373                 {
  1374                     gpgme_key_t key = NULL;
  1375 
  1376                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1377                         import->fpr, &key, 0);
  1378                     gpgme_error = _GPGERR(gpgme_error);
  1379                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1380                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1381                         gpg.gpgme_data_release(dh);
  1382                         return PEP_OUT_OF_MEMORY;
  1383                     }
  1384 
  1385                     if (gpgme_error == GPG_ERR_NO_ERROR &&
  1386                         key && key->uids &&
  1387                         key->uids->email && key->uids->name)
  1388                     {
  1389                         pEp_identity *ident = new_identity(
  1390                              key->uids->email, import->fpr, NULL, key->uids->name);
  1391 
  1392                         gpg.gpgme_key_unref(key);
  1393 
  1394                         if (ident == NULL) {
  1395                             gpg.gpgme_data_release(dh);
  1396                             return PEP_OUT_OF_MEMORY;
  1397                         }
  1398 
  1399                         *private_idents = identity_list_add(*private_idents, ident);
  1400 
  1401                         if (*private_idents == NULL) {
  1402                             gpg.gpgme_data_release(dh);
  1403                             return PEP_OUT_OF_MEMORY;
  1404                         }
  1405                     }
  1406                     else
  1407                     {
  1408                         gpg.gpgme_key_unref(key);
  1409                         gpg.gpgme_data_release(dh);
  1410                         return PEP_UNKNOWN_ERROR;
  1411                     }
  1412                 }
  1413             }
  1414         }
  1415         break;
  1416     case GPG_ERR_INV_VALUE:
  1417         assert(0);
  1418         gpg.gpgme_data_release(dh);
  1419         return PEP_UNKNOWN_ERROR;
  1420     case GPG_ERR_NO_DATA:
  1421         gpg.gpgme_data_release(dh);
  1422         return PEP_ILLEGAL_VALUE;
  1423     default:
  1424         assert(0);
  1425         gpg.gpgme_data_release(dh);
  1426         return PEP_UNKNOWN_ERROR;
  1427     }
  1428 
  1429     gpg.gpgme_data_release(dh);
  1430     return PEP_STATUS_OK;
  1431 }
  1432 
  1433 PEP_STATUS pgp_export_keydata(
  1434         PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
  1435         bool secret
  1436     )
  1437 {
  1438     gpgme_error_t gpgme_error;
  1439     gpgme_data_t dh;
  1440     size_t _size;
  1441     char *buffer;
  1442     int reading;
  1443 
  1444     assert(session);
  1445     assert(fpr);
  1446     assert(key_data);
  1447     assert(size);
  1448 
  1449     gpgme_error = gpg.gpgme_data_new(&dh);
  1450     gpgme_error = _GPGERR(gpgme_error);
  1451     assert(gpgme_error != GPG_ERR_ENOMEM);
  1452     switch (gpgme_error) {
  1453     case GPG_ERR_NO_ERROR:
  1454         break;
  1455     case GPG_ERR_ENOMEM:
  1456         return PEP_OUT_OF_MEMORY;
  1457     case GPG_ERR_INV_VALUE:
  1458         assert(0);
  1459         return PEP_UNKNOWN_ERROR;
  1460     default:
  1461         assert(0);
  1462         return PEP_UNKNOWN_ERROR;
  1463     }
  1464 
  1465     if (secret)
  1466         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1467             GPGME_EXPORT_MODE_SECRET, dh);
  1468     else
  1469         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1470             GPGME_EXPORT_MODE_MINIMAL, dh);
  1471     gpgme_error = _GPGERR(gpgme_error);
  1472     switch (gpgme_error) {
  1473     case GPG_ERR_NO_ERROR:
  1474         break;
  1475     case GPG_ERR_EOF:
  1476         gpg.gpgme_data_release(dh);
  1477         return PEP_KEY_NOT_FOUND;
  1478     case GPG_ERR_INV_VALUE:
  1479         assert(0);
  1480         gpg.gpgme_data_release(dh);
  1481         return PEP_UNKNOWN_ERROR;
  1482     default:
  1483         assert(0);
  1484         gpg.gpgme_data_release(dh);
  1485         return PEP_UNKNOWN_ERROR;
  1486     };
  1487 
  1488     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1489     assert(_size != -1);
  1490     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1491 
  1492     buffer = malloc(_size + 1);
  1493     assert(buffer);
  1494     if (buffer == NULL) {
  1495         gpg.gpgme_data_release(dh);
  1496         return PEP_OUT_OF_MEMORY;
  1497     }
  1498 
  1499     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1500     assert(_size == reading);
  1501 
  1502     // safeguard for the naive user
  1503     buffer[_size] = 0;
  1504 
  1505     *key_data = buffer;
  1506     *size = _size;
  1507 
  1508     gpg.gpgme_data_release(dh);
  1509     return PEP_STATUS_OK;
  1510 }
  1511 
  1512 PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
  1513                             stringpair_list_t** keyinfo_list)
  1514 {
  1515     gpgme_error_t gpgme_error;
  1516     assert(session);
  1517     assert(keyinfo_list);
  1518 
  1519     if (!session || !keyinfo_list)
  1520         return PEP_ILLEGAL_VALUE;
  1521 
  1522     *keyinfo_list = NULL;
  1523 
  1524     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1525     gpgme_error = _GPGERR(gpgme_error);
  1526 
  1527     switch(gpgme_error) {
  1528         case GPG_ERR_NO_ERROR:
  1529             break;
  1530         case GPG_ERR_INV_VALUE:
  1531             assert(0);
  1532             return PEP_UNKNOWN_ERROR;
  1533         default:
  1534             gpg.gpgme_op_keylist_end(session->ctx);
  1535             return PEP_GET_KEY_FAILED;
  1536     };
  1537 
  1538     gpgme_key_t key;
  1539     stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
  1540     stringpair_list_t* list_curr = _keyinfo_list;
  1541     stringpair_t* pair = NULL;
  1542 
  1543     do {
  1544         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1545         gpgme_error = _GPGERR(gpgme_error);
  1546 
  1547         switch(gpgme_error) {
  1548             case GPG_ERR_EOF:
  1549                 break;
  1550             case GPG_ERR_NO_ERROR:
  1551                 assert(key);
  1552                 assert(key->subkeys);
  1553                 if (!key || !key->subkeys)
  1554                     return PEP_GET_KEY_FAILED;
  1555 
  1556                 // first subkey is primary key
  1557                 char* fpr = key->subkeys->fpr;
  1558                 char* uid = key->uids->uid;
  1559 
  1560                 assert(fpr);
  1561                 assert(uid);
  1562                 if (!fpr)
  1563                     return PEP_GET_KEY_FAILED;
  1564 
  1565                 if (key->subkeys->revoked)
  1566                     continue;
  1567 
  1568                 pair = new_stringpair(fpr, uid);
  1569 
  1570                 assert(pair);
  1571 
  1572                 if (pair) {
  1573                     list_curr = stringpair_list_add(list_curr, pair);
  1574                     pair = NULL;
  1575 
  1576                     assert(list_curr);
  1577                     if (list_curr != NULL)
  1578                         break;
  1579                     else
  1580                         free_stringpair(pair);
  1581                 }
  1582                 // else fallthrough (list_curr or pair wasn't allocateable)
  1583             case GPG_ERR_ENOMEM:
  1584                 free_stringpair_list(_keyinfo_list);
  1585                 gpg.gpgme_op_keylist_end(session->ctx);
  1586                 return PEP_OUT_OF_MEMORY;
  1587             default:
  1588                 gpg.gpgme_op_keylist_end(session->ctx);
  1589                 return PEP_UNKNOWN_ERROR;
  1590         }
  1591     } while (gpgme_error != GPG_ERR_EOF);
  1592 
  1593     if (_keyinfo_list->value == NULL) {
  1594         free_stringpair_list(_keyinfo_list);
  1595         _keyinfo_list = NULL;
  1596     }
  1597 
  1598     *keyinfo_list = _keyinfo_list;
  1599 
  1600     return PEP_STATUS_OK;
  1601 }
  1602 
  1603 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1604     gpgme_keylist_mode_t add_mode)
  1605 {
  1606     gpgme_error_t gpgme_error;
  1607     gpgme_keylist_mode_t mode;
  1608 
  1609     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1610 
  1611     mode &= ~remove_mode;
  1612     mode |= add_mode;
  1613 
  1614     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1615     gpgme_error = _GPGERR(gpgme_error);
  1616     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1617 }
  1618 
  1619 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1620 {
  1621     gpgme_error_t gpgme_error;
  1622     gpgme_key_t key;
  1623 
  1624     assert(session);
  1625     assert(pattern);
  1626 
  1627     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1628 
  1629     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1630     gpgme_error = _GPGERR(gpgme_error);
  1631     switch (gpgme_error) {
  1632     case GPG_ERR_NO_ERROR:
  1633         break;
  1634     case GPG_ERR_INV_VALUE:
  1635         assert(0);
  1636         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1637         return PEP_UNKNOWN_ERROR;
  1638     default:
  1639         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1640         return PEP_GET_KEY_FAILED;
  1641     };
  1642 
  1643     gpgme_ctx_t import_ctx;
  1644     gpgme_error = gpg.gpgme_new(&import_ctx);
  1645     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1646 
  1647     do {
  1648         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1649         gpgme_error = _GPGERR(gpgme_error);
  1650         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1651         switch (gpgme_error) {
  1652         case GPG_ERR_EOF:
  1653             break;
  1654         case GPG_ERR_NO_ERROR:
  1655         {
  1656             gpgme_error_t gpgme_error;
  1657             gpgme_key_t keys[2];
  1658 
  1659             keys[0] = key;
  1660             keys[1] = NULL;
  1661 
  1662             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1663             gpgme_error = _GPGERR(gpgme_error);
  1664             gpg.gpgme_key_unref(key);
  1665             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1666             assert(gpgme_error != GPG_ERR_CONFLICT);
  1667         }
  1668             break;
  1669         case GPG_ERR_ENOMEM:
  1670             gpg.gpgme_op_keylist_end(session->ctx);
  1671             gpg.gpgme_release(import_ctx);
  1672             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1673             return PEP_OUT_OF_MEMORY;
  1674         default:
  1675             gpg.gpgme_op_keylist_end(session->ctx);
  1676             gpg.gpgme_release(import_ctx);
  1677             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1678             return PEP_UNKNOWN_ERROR;
  1679         };
  1680     } while (gpgme_error != GPG_ERR_EOF);
  1681 
  1682     gpg.gpgme_op_keylist_end(session->ctx);
  1683     gpg.gpgme_release(import_ctx);
  1684     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1685     return PEP_STATUS_OK;
  1686 }
  1687 
  1688 
  1689 static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
  1690                             stringlist_t** keylist,
  1691                             int private_only) {
  1692     gpgme_error_t gpgme_error;
  1693     gpgme_key_t key;
  1694 
  1695     assert(session);
  1696     assert(pattern);
  1697     assert(keylist);
  1698 
  1699     *keylist = NULL;
  1700 
  1701     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
  1702     gpgme_error = _GPGERR(gpgme_error);
  1703     switch (gpgme_error) {
  1704         case GPG_ERR_NO_ERROR:
  1705             break;
  1706         case GPG_ERR_INV_VALUE:
  1707             assert(0);
  1708             return PEP_UNKNOWN_ERROR;
  1709         default:
  1710             gpg.gpgme_op_keylist_end(session->ctx);
  1711             return PEP_GET_KEY_FAILED;
  1712     };
  1713 
  1714     stringlist_t *_keylist = new_stringlist(NULL);
  1715     stringlist_t *_k = _keylist;
  1716 
  1717     do {
  1718         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1719         gpgme_error = _GPGERR(gpgme_error);
  1720         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1721         switch (gpgme_error) {
  1722             case GPG_ERR_EOF:
  1723                 break;
  1724             case GPG_ERR_NO_ERROR:
  1725                 assert(key);
  1726                 assert(key->subkeys);
  1727                 if(!key->subkeys)
  1728                     break;
  1729                 assert(key->uids);
  1730                 gpgme_user_id_t kuid = key->uids;
  1731                 // check that at least one uid's email matches pattern exactly
  1732                 while(kuid) {
  1733                     if(kuid->email && strcmp(kuid->email, pattern) == 0){
  1734                         char *fpr = key->subkeys->fpr;
  1735                         assert(fpr);
  1736                         _k = stringlist_add(_k, fpr);
  1737                         assert(_k);
  1738                         if (_k == NULL){
  1739                             free_stringlist(_keylist);
  1740                             gpg.gpgme_op_keylist_end(session->ctx);
  1741                             return PEP_OUT_OF_MEMORY;
  1742                         }
  1743                         break;
  1744                     }
  1745                     kuid = kuid->next;
  1746                 }
  1747                 break;
  1748             case GPG_ERR_ENOMEM:
  1749                 free_stringlist(_keylist);
  1750                 gpg.gpgme_op_keylist_end(session->ctx);
  1751                 return PEP_OUT_OF_MEMORY;
  1752             default:
  1753                 gpg.gpgme_op_keylist_end(session->ctx);
  1754                 return PEP_UNKNOWN_ERROR;
  1755         };
  1756     } while (gpgme_error != GPG_ERR_EOF);
  1757 
  1758     gpg.gpgme_op_keylist_end(session->ctx);
  1759     if (_keylist->value == NULL) {
  1760         free_stringlist(_keylist);
  1761         _keylist = NULL;
  1762     }
  1763     *keylist = _keylist;
  1764     return PEP_STATUS_OK;
  1765 }
  1766 
  1767 PEP_STATUS pgp_find_keys(
  1768     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1769     )
  1770 {
  1771     return _pgp_search_keys(session, pattern, keylist, 0);
  1772 }
  1773 
  1774 PEP_STATUS pgp_find_private_keys(
  1775     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1776 )
  1777 {
  1778     return _pgp_search_keys(session, pattern, keylist, 1);
  1779 }
  1780 
  1781 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1782 {
  1783     gpgme_error_t gpgme_error;
  1784 
  1785     assert(session);
  1786     assert(pattern);
  1787 
  1788     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  1789         GPGME_EXPORT_MODE_EXTERN, NULL);
  1790     gpgme_error = _GPGERR(gpgme_error);
  1791     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1792     if (gpgme_error == GPG_ERR_NO_ERROR)
  1793         return PEP_STATUS_OK;
  1794     else
  1795         return PEP_CANNOT_SEND_KEY;
  1796 }
  1797 
  1798 PEP_STATUS pgp_get_key_rating(
  1799     PEP_SESSION session,
  1800     const char *fpr,
  1801     PEP_comm_type *comm_type
  1802     )
  1803 {
  1804     PEP_STATUS status = PEP_STATUS_OK;
  1805     gpgme_error_t gpgme_error;
  1806     gpgme_key_t key;
  1807 
  1808     assert(session);
  1809     assert(fpr);
  1810     assert(comm_type);
  1811 
  1812     *comm_type = PEP_ct_unknown;
  1813 
  1814     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1815     gpgme_error = _GPGERR(gpgme_error);
  1816     switch (gpgme_error) {
  1817     case GPG_ERR_NO_ERROR:
  1818         break;
  1819     case GPG_ERR_INV_VALUE:
  1820         assert(0);
  1821         return PEP_UNKNOWN_ERROR;
  1822     default:
  1823         return PEP_GET_KEY_FAILED;
  1824     };
  1825 
  1826     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1827     gpgme_error = _GPGERR(gpgme_error);
  1828     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1829 
  1830     if (key == NULL) {
  1831         gpg.gpgme_op_keylist_end(session->ctx);
  1832         return PEP_KEY_NOT_FOUND;
  1833     }
  1834 
  1835     switch (key->protocol) {
  1836     case GPGME_PROTOCOL_OpenPGP:
  1837     case GPGME_PROTOCOL_DEFAULT:
  1838         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1839         break;
  1840     case GPGME_PROTOCOL_CMS:
  1841         *comm_type = PEP_ct_CMS_unconfirmed;
  1842         break;
  1843     default:
  1844         *comm_type = PEP_ct_unknown;
  1845         gpg.gpgme_op_keylist_end(session->ctx);
  1846         return PEP_STATUS_OK;
  1847     }
  1848 
  1849     switch (gpgme_error) {
  1850     case GPG_ERR_EOF:
  1851         break;
  1852     case GPG_ERR_NO_ERROR:
  1853         assert(key);
  1854         assert(key->subkeys);
  1855         for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  1856             if (sk->length < 1024)
  1857                 *comm_type = PEP_ct_key_too_short;
  1858             else if (
  1859                 (
  1860                 (sk->pubkey_algo == GPGME_PK_RSA)
  1861                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  1862                 || (sk->pubkey_algo == GPGME_PK_RSA_S)
  1863                 )
  1864                 && sk->length == 1024
  1865                 )
  1866                 *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1867 
  1868             if (sk->invalid) {
  1869                 *comm_type = PEP_ct_key_b0rken;
  1870                 break;
  1871             }
  1872             if (sk->expired) {
  1873                 *comm_type = PEP_ct_key_expired;
  1874                 break;
  1875             }
  1876             if (sk->revoked) {
  1877                 *comm_type = PEP_ct_key_revoked;
  1878                 break;
  1879             }
  1880         }
  1881         break;
  1882     case GPG_ERR_ENOMEM:
  1883         gpg.gpgme_op_keylist_end(session->ctx);
  1884         *comm_type = PEP_ct_unknown;
  1885         return PEP_OUT_OF_MEMORY;
  1886     default:
  1887         gpg.gpgme_op_keylist_end(session->ctx);
  1888         return PEP_UNKNOWN_ERROR;
  1889     };
  1890 
  1891     gpg.gpgme_op_keylist_end(session->ctx);
  1892 
  1893     return status;
  1894 }
  1895 
  1896 static PEP_STATUS find_single_key(
  1897         PEP_SESSION session,
  1898         const char *fpr,
  1899         gpgme_key_t *key
  1900     )
  1901 {
  1902     gpgme_error_t gpgme_error;
  1903 
  1904     *key = NULL;
  1905 
  1906     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1907     gpgme_error = _GPGERR(gpgme_error);
  1908     switch (gpgme_error) {
  1909     case GPG_ERR_NO_ERROR:
  1910         break;
  1911     case GPG_ERR_INV_VALUE:
  1912         assert(0);
  1913         return PEP_UNKNOWN_ERROR;
  1914     default:
  1915         return PEP_GET_KEY_FAILED;
  1916     };
  1917 
  1918     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1919     gpgme_error = _GPGERR(gpgme_error);
  1920     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1921 
  1922     gpg.gpgme_op_keylist_end(session->ctx);
  1923 
  1924     return PEP_STATUS_OK;
  1925 }
  1926 
  1927 typedef struct _renew_state {
  1928     enum {
  1929         renew_command = 0,
  1930         renew_date,
  1931         renew_secret_key,
  1932         renew_command2,
  1933         renew_date2,
  1934         renew_quit,
  1935         renew_save,
  1936         renew_exit,
  1937         renew_error = -1
  1938     } state;
  1939     const char *date_ref;
  1940 } renew_state;
  1941 
  1942 static gpgme_error_t renew_fsm(
  1943         void *_handle,
  1944         gpgme_status_code_t statuscode,
  1945         const char *args,
  1946         int fd
  1947     )
  1948 {
  1949     renew_state *handle = _handle;
  1950 
  1951     switch (handle->state) {
  1952         case renew_command:
  1953             if (statuscode == GPGME_STATUS_GET_LINE) {
  1954                 assert(strcmp(args, "keyedit.prompt") == 0);
  1955                 if (strcmp(args, "keyedit.prompt")) {
  1956                     handle->state = renew_error;
  1957                     return GPG_ERR_GENERAL;
  1958                 }
  1959                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1960                 handle->state = renew_date;
  1961             }
  1962             break;
  1963 
  1964         case renew_date:
  1965             if (statuscode == GPGME_STATUS_GET_LINE) {
  1966                 assert(strcmp(args, "keygen.valid") == 0);
  1967                 if (strcmp(args, "keygen.valid")) {
  1968                     handle->state = renew_error;
  1969                     return GPG_ERR_GENERAL;
  1970                 }
  1971                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1972                 handle->state = renew_secret_key;
  1973             }
  1974             break;
  1975 
  1976         case renew_secret_key:
  1977             if (statuscode == GPGME_STATUS_GET_LINE) {
  1978                 assert(strcmp(args, "keyedit.prompt") == 0);
  1979                 if (strcmp(args, "keyedit.prompt")) {
  1980                     handle->state = renew_error;
  1981                     return GPG_ERR_GENERAL;
  1982                 }
  1983                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  1984                 handle->state = renew_command2;
  1985             }
  1986             break;
  1987 
  1988         case renew_command2:
  1989             if (statuscode == GPGME_STATUS_GET_LINE) {
  1990                 assert(strcmp(args, "keyedit.prompt") == 0);
  1991                 if (strcmp(args, "keyedit.prompt")) {
  1992                     handle->state = renew_error;
  1993                     return GPG_ERR_GENERAL;
  1994                 }
  1995                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1996                 handle->state = renew_date2;
  1997             }
  1998             break;
  1999 
  2000         case renew_date2:
  2001             if (statuscode == GPGME_STATUS_GET_LINE) {
  2002                 assert(strcmp(args, "keygen.valid") == 0);
  2003                 if (strcmp(args, "keygen.valid")) {
  2004                     handle->state = renew_error;
  2005                     return GPG_ERR_GENERAL;
  2006                 }
  2007                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2008                 handle->state = renew_quit;
  2009             }
  2010             break;
  2011 
  2012         case renew_quit:
  2013             if (statuscode == GPGME_STATUS_GET_LINE) {
  2014                 assert(strcmp(args, "keyedit.prompt") == 0);
  2015                 if (strcmp(args, "keyedit.prompt")) {
  2016                     handle->state = renew_error;
  2017                     return GPG_ERR_GENERAL;
  2018                 }
  2019                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2020                 handle->state = renew_save;
  2021             }
  2022             break;
  2023 
  2024         case renew_save:
  2025             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2026                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2027                 if (strcmp(args, "keyedit.save.okay")) {
  2028                     handle->state = renew_error;
  2029                     return GPG_ERR_GENERAL;
  2030                 }
  2031                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2032                 handle->state = renew_exit;
  2033             }
  2034             break;
  2035 
  2036         case renew_exit:
  2037             break;
  2038 
  2039         case renew_error:
  2040             return GPG_ERR_GENERAL;
  2041     }
  2042 
  2043     return GPG_ERR_NO_ERROR;
  2044 }
  2045 
  2046 static ssize_t _nullwriter(
  2047         void *_handle,
  2048         const void *buffer,
  2049         size_t size
  2050     )
  2051 {
  2052     return size;
  2053 }
  2054 
  2055 PEP_STATUS pgp_renew_key(
  2056         PEP_SESSION session,
  2057         const char *fpr,
  2058         const timestamp *ts
  2059     )
  2060 {
  2061     PEP_STATUS status = PEP_STATUS_OK;
  2062     gpgme_error_t gpgme_error;
  2063     gpgme_key_t key;
  2064     gpgme_data_t output;
  2065     renew_state handle;
  2066     char date_text[12];
  2067 
  2068     assert(session);
  2069     assert(fpr);
  2070 
  2071     memset(&handle, 0, sizeof(renew_state));
  2072     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  2073             ts->tm_mon + 1, ts->tm_mday);
  2074     handle.date_ref = date_text;
  2075 
  2076     status = find_single_key(session, fpr, &key);
  2077     if (status != PEP_STATUS_OK)
  2078         return status;
  2079 
  2080     struct gpgme_data_cbs data_cbs;
  2081     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2082     data_cbs.write = _nullwriter;
  2083     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2084 
  2085     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  2086             output);
  2087     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2088 
  2089     gpg.gpgme_data_release(output);
  2090     gpg.gpgme_key_unref(key);
  2091 
  2092     return PEP_STATUS_OK;
  2093 }
  2094 
  2095 typedef struct _revoke_state {
  2096     enum {
  2097         revoke_command = 0,
  2098         revoke_approve,
  2099         revoke_reason_code,
  2100         revoke_reason_text,
  2101         revoke_reason_ok,
  2102         revoke_quit,
  2103         revoke_save,
  2104         revoke_exit,
  2105         revoke_error = -1
  2106     } state;
  2107     const char *reason_ref;
  2108 } revoke_state;
  2109 
  2110 
  2111 /*** unused?
  2112 static bool isemptystring(const char *str)
  2113 {
  2114     if (str == NULL)
  2115         return true;
  2116 
  2117     for (; str; str++) {
  2118         if (*str != ' ' && *str != '\t' && *str != '\n')
  2119             return false;
  2120     }
  2121 
  2122     return true;
  2123 }
  2124 ***/
  2125 
  2126 
  2127 static gpgme_error_t revoke_fsm(
  2128         void *_handle,
  2129         gpgme_status_code_t statuscode,
  2130         const char *args,
  2131         int fd
  2132     )
  2133 {
  2134     revoke_state *handle = _handle;
  2135 
  2136     switch (handle->state) {
  2137         case revoke_command:
  2138             if (statuscode == GPGME_STATUS_GET_LINE) {
  2139                 assert(strcmp(args, "keyedit.prompt") == 0);
  2140                 if (strcmp(args, "keyedit.prompt")) {
  2141                     handle->state = revoke_error;
  2142                     return GPG_ERR_GENERAL;
  2143                 }
  2144                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  2145                 handle->state = revoke_approve;
  2146             }
  2147             break;
  2148 
  2149         case revoke_approve:
  2150             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2151                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  2152                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  2153                     handle->state = revoke_error;
  2154                     return GPG_ERR_GENERAL;
  2155                 }
  2156                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2157                 handle->state = revoke_reason_code;
  2158             }
  2159             break;
  2160 
  2161         case revoke_reason_code:
  2162             if (statuscode == GPGME_STATUS_GET_LINE) {
  2163                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  2164                 if (strcmp(args, "ask_revocation_reason.code")) {
  2165                     handle->state = revoke_error;
  2166                     return GPG_ERR_GENERAL;
  2167                 }
  2168                 gpg.gpgme_io_write(fd, "1\n", 2);
  2169                 handle->state = revoke_reason_text;
  2170             }
  2171             break;
  2172 
  2173         case revoke_reason_text:
  2174             if (statuscode == GPGME_STATUS_GET_LINE) {
  2175                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  2176                 if (strcmp(args, "ask_revocation_reason.text")) {
  2177                     handle->state = revoke_error;
  2178                     return GPG_ERR_GENERAL;
  2179                 }
  2180                 // BUG: issues when reason given
  2181                 // Assertion failed: (gpg->cmd.code), function command_handler,
  2182                 // file engine-gpg.c, line 662.
  2183                 //
  2184                 // if (isemptystring(handle->reason_ref)) {
  2185                     gpg.gpgme_io_write(fd, "\n", 1);
  2186                 // }
  2187                 // else {
  2188                 //     size_t len = strlen(handle->reason_ref);
  2189                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  2190                 //     if (handle->reason_ref[len - 1] == '\n')
  2191                 //         gpg.gpgme_io_write(fd, "\n", 1);
  2192                 //     else
  2193                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  2194                 // }
  2195                 handle->state = revoke_reason_ok;
  2196             }
  2197             break;
  2198 
  2199         case revoke_reason_ok:
  2200             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2201                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  2202                 if (strcmp(args, "ask_revocation_reason.okay")) {
  2203                     handle->state = revoke_error;
  2204                     return GPG_ERR_GENERAL;
  2205                 }
  2206                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2207                 handle->state = revoke_quit;
  2208             }
  2209             break;
  2210 
  2211         case revoke_quit:
  2212             if (statuscode == GPGME_STATUS_GET_LINE) {
  2213                 assert(strcmp(args, "keyedit.prompt") == 0);
  2214                 if (strcmp(args, "keyedit.prompt")) {
  2215                     handle->state = revoke_error;
  2216                     return GPG_ERR_GENERAL;
  2217                 }
  2218                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2219                 handle->state = revoke_save;
  2220             }
  2221             break;
  2222 
  2223         case revoke_save:
  2224             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2225                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2226                 if (strcmp(args, "keyedit.save.okay")) {
  2227                     handle->state = revoke_error;
  2228                     return GPG_ERR_GENERAL;
  2229                 }
  2230                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2231                 handle->state = revoke_exit;
  2232             }
  2233             break;
  2234 
  2235         case revoke_exit:
  2236             break;
  2237 
  2238         case revoke_error:
  2239             return GPG_ERR_GENERAL;
  2240     }
  2241 
  2242     return GPG_ERR_NO_ERROR;
  2243 }
  2244 
  2245 PEP_STATUS pgp_revoke_key(
  2246         PEP_SESSION session,
  2247         const char *fpr,
  2248         const char *reason
  2249     )
  2250 {
  2251     PEP_STATUS status = PEP_STATUS_OK;
  2252     gpgme_error_t gpgme_error;
  2253     gpgme_key_t key;
  2254     gpgme_data_t output;
  2255     revoke_state handle;
  2256 
  2257     assert(session);
  2258     assert(fpr);
  2259 
  2260     memset(&handle, 0, sizeof(revoke_state));
  2261     handle.reason_ref = reason;
  2262 
  2263     status = find_single_key(session, fpr, &key);
  2264     if (status != PEP_STATUS_OK)
  2265         return status;
  2266 
  2267     struct gpgme_data_cbs data_cbs;
  2268     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2269     data_cbs.write = _nullwriter;
  2270     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2271 
  2272     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  2273             output);
  2274     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2275 
  2276     gpg.gpgme_data_release(output);
  2277     gpg.gpgme_key_unref(key);
  2278 
  2279     return PEP_STATUS_OK;
  2280 }
  2281 
  2282 PEP_STATUS pgp_key_expired(
  2283         PEP_SESSION session,
  2284         const char *fpr,
  2285         const time_t when,
  2286         bool *expired
  2287     )
  2288 {
  2289     PEP_STATUS status = PEP_STATUS_OK;
  2290     gpgme_key_t key;
  2291 
  2292     assert(session);
  2293     assert(fpr);
  2294     assert(expired);
  2295 
  2296     *expired = false;
  2297 
  2298     status = find_single_key(session, fpr, &key);
  2299     if (status != PEP_STATUS_OK)
  2300         return status;
  2301 
  2302     if ((key && key->expired) ||
  2303         (key && key->subkeys && key->subkeys->expired))
  2304     {
  2305         // Already marked expired
  2306         *expired = 1;
  2307     }
  2308     else if (key)
  2309     {
  2310         // Detect if will be expired
  2311         // i.e. Check that keys capabilities will
  2312         // not be expired at given time.
  2313         gpgme_subkey_t _sk;
  2314         bool crt_available = false;
  2315         bool sgn_available = false;
  2316         bool enc_available = false;
  2317         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  2318             if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
  2319                                                           // Also, zero means "does not expire"
  2320             {
  2321                 if (_sk->can_certify) crt_available = true;
  2322                 if (_sk->can_sign) sgn_available = true;
  2323                 if (_sk->can_encrypt) enc_available = true;
  2324                 // Authenticate is not used here.
  2325             }
  2326         }
  2327         if(!(crt_available && sgn_available && enc_available))
  2328         {
  2329             *expired = 1;
  2330         }
  2331     }
  2332     else
  2333     {
  2334         status = PEP_KEY_NOT_FOUND;
  2335     }
  2336 
  2337     gpg.gpgme_key_unref(key);
  2338     return status;
  2339 }
  2340 
  2341 PEP_STATUS pgp_key_revoked(
  2342         PEP_SESSION session,
  2343         const char *fpr,
  2344         bool *revoked
  2345     )
  2346 {
  2347     PEP_STATUS status = PEP_STATUS_OK;
  2348     gpgme_key_t key;
  2349 
  2350     assert(session);
  2351     assert(fpr);
  2352     assert(revoked);
  2353 
  2354     *revoked = false;
  2355 
  2356     status = find_single_key(session, fpr, &key);
  2357     if (status != PEP_STATUS_OK)
  2358         return status;
  2359 
  2360     if (key && key->subkeys)
  2361     {
  2362         *revoked = key->subkeys->revoked;
  2363     }
  2364     else
  2365     {
  2366         status = PEP_KEY_NOT_FOUND;
  2367     }
  2368 
  2369     gpg.gpgme_key_unref(key);
  2370     return status;
  2371 }
  2372 
  2373 PEP_STATUS pgp_key_created(
  2374         PEP_SESSION session,
  2375         const char *fpr,
  2376         time_t *created
  2377     )
  2378 {
  2379     PEP_STATUS status = PEP_STATUS_OK;
  2380     gpgme_key_t key;
  2381 
  2382     assert(session);
  2383     assert(fpr);
  2384     assert(created);
  2385 
  2386     *created = 0;
  2387 
  2388     status = find_single_key(session, fpr, &key);
  2389     if (status != PEP_STATUS_OK)
  2390         return status;
  2391 
  2392     if (key && key->subkeys)
  2393     {
  2394         *created = (time_t) key->subkeys->timestamp;
  2395     }
  2396     else
  2397     {
  2398         status = PEP_KEY_NOT_FOUND;
  2399     }
  2400 
  2401     gpg.gpgme_key_unref(key);
  2402     return status;
  2403 }
  2404 
  2405 PEP_STATUS pgp_binary(const char **path)
  2406 {
  2407     assert(path);
  2408     if (path == NULL)
  2409         return PEP_ILLEGAL_VALUE;
  2410 
  2411     *path = NULL;
  2412 
  2413     gpgme_engine_info_t info;
  2414     int err = gpg.gpgme_get_engine_info(&info);
  2415     assert(err == GPG_ERR_NO_ERROR);
  2416     if (err != GPG_ERR_NO_ERROR)
  2417         return PEP_OUT_OF_MEMORY;
  2418 
  2419     *path = info->file_name;
  2420 
  2421     return PEP_STATUS_OK;
  2422 }
  2423 
  2424 PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
  2425         bool *has_private) {
  2426     PEP_STATUS status = PEP_STATUS_OK;
  2427     gpgme_key_t output_key;
  2428     gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
  2429     *has_private = false;
  2430     switch (gpgerr) {
  2431         case GPG_ERR_EOF:
  2432         case GPG_ERR_INV_VALUE:
  2433             status = PEP_KEY_NOT_FOUND;
  2434             break;
  2435         case GPG_ERR_AMBIGUOUS_NAME:
  2436             status = PEP_KEY_HAS_AMBIG_NAME;
  2437             break;
  2438         case GPG_ERR_NO_ERROR:
  2439             *has_private = true;
  2440             gpg.gpgme_key_release(output_key);
  2441             break;
  2442         case GPG_ERR_ENOMEM:
  2443             status = PEP_OUT_OF_MEMORY;
  2444             break;
  2445         default:
  2446             status = PEP_UNKNOWN_ERROR;
  2447             break;
  2448     }
  2449     return status;
  2450 }