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