src/pgp_gpg.c
author Krista Bennett <krista@pep-project.org>
Wed, 12 Jul 2017 14:01:26 +0200
branchgnupg-2.1
changeset 1914 e40bb1f761fe
parent 1803 656f58b5b244
child 1920 c7e8570c9d25
permissions -rw-r--r--
attempting changes for keygen w/ 2.1
     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 static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
  1064     PEP_STATUS status = PEP_VERSION_MISMATCH;
  1065 
  1066     if (identity && identity->address) {
  1067     
  1068 #ifdef GPGME_VERSION_NUMBER 
  1069 #if (GPGME_VERSION_NUMBER >= 0x010700)
  1070     gpgme_error_t gpgme_error;
  1071     gpgme_error = gpg.gpgme_op_createkey(session->ctx, identity->address, "RSA", 
  1072                                          0, 31536000, NULL, GPGME_CREATE_NOPASSWD);
  1073     gpgme_error = _GPGERR(gpgme_error);
  1074     if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
  1075         switch (gpgme_error) {
  1076         case GPG_ERR_NO_ERROR:
  1077             break;
  1078         case GPG_ERR_INV_VALUE:
  1079             return PEP_ILLEGAL_VALUE;
  1080         case GPG_ERR_GENERAL:
  1081             return PEP_CANNOT_CREATE_KEY;
  1082         default:
  1083             assert(0);
  1084             return PEP_UNKNOWN_ERROR;
  1085         }        
  1086     }
  1087 #endif
  1088 #endif
  1089 
  1090     }
  1091     
  1092     return status;
  1093 }
  1094 
  1095 PEP_STATUS pgp_generate_keypair(
  1096     PEP_SESSION session, pEp_identity *identity
  1097     )
  1098 {
  1099     assert(session);
  1100     assert(identity);
  1101     assert(identity->address);
  1102     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1103     assert(identity->username);
  1104 
  1105     PEP_STATUS status = _pgp_createkey(session, identity);
  1106     
  1107     if (status != PEP_STATUS_OK || 
  1108         status != PEP_VERSION_MISMATCH)
  1109         return status;
  1110 
  1111     if (status == PEP_VERSION_MISMATCH) {
  1112         gpgme_error_t gpgme_error;
  1113         char *parms;
  1114         const char *template =
  1115             "<GnupgKeyParms format=\"internal\">\n"
  1116             "Key-Type: RSA\n"
  1117             "Key-Length: 4096\n"
  1118             "Subkey-Type: RSA\n"
  1119             "Subkey-Length: 4096\n"
  1120             "Name-Real: %s\n"
  1121             "Name-Email: %s\n"
  1122             /* "Passphrase: %s\n" */
  1123             "Expire-Date: 1y\n"
  1124             "</GnupgKeyParms>\n";
  1125         int result;
  1126     
  1127         parms = calloc(1, PARMS_MAX);
  1128         assert(parms);
  1129         if (parms == NULL)
  1130             return PEP_OUT_OF_MEMORY;
  1131 
  1132         result = snprintf(parms, PARMS_MAX, template, identity->username,
  1133             identity->address); // , session->passphrase);
  1134         assert(result < PARMS_MAX);
  1135         if (result >= PARMS_MAX) {
  1136             free(parms);
  1137             return PEP_BUFFER_TOO_SMALL;
  1138         }
  1139 
  1140         gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
  1141         gpgme_error = _GPGERR(gpgme_error);
  1142         free(parms);
  1143 
  1144         switch (gpgme_error) {
  1145         case GPG_ERR_NO_ERROR:
  1146             break;
  1147         case GPG_ERR_INV_VALUE:
  1148             return PEP_ILLEGAL_VALUE;
  1149         case GPG_ERR_GENERAL:
  1150             return PEP_CANNOT_CREATE_KEY;
  1151         default:
  1152             assert(0);
  1153             return PEP_UNKNOWN_ERROR;
  1154         }
  1155     }
  1156 
  1157     /* This is the same regardless of whether we got it from genkey or createkey */
  1158     gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1159     assert(gpgme_genkey_result);
  1160     assert(gpgme_genkey_result->fpr);
  1161 
  1162     free(identity->fpr);
  1163     identity->fpr = strdup(gpgme_genkey_result->fpr);
  1164     if (identity->fpr == NULL)
  1165         return PEP_OUT_OF_MEMORY;
  1166 
  1167     return PEP_STATUS_OK;
  1168 }
  1169 
  1170 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
  1171 {
  1172     gpgme_error_t gpgme_error;
  1173     gpgme_key_t key;
  1174 
  1175     assert(session);
  1176     assert(fpr);
  1177 
  1178     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1179     gpgme_error = _GPGERR(gpgme_error);
  1180     assert(gpgme_error != GPG_ERR_ENOMEM);
  1181     switch (gpgme_error) {
  1182     case GPG_ERR_NO_ERROR:
  1183         break;
  1184     case GPG_ERR_EOF:
  1185         return PEP_KEY_NOT_FOUND;
  1186     case GPG_ERR_INV_VALUE:
  1187         return PEP_ILLEGAL_VALUE;
  1188     case GPG_ERR_AMBIGUOUS_NAME:
  1189         return PEP_KEY_HAS_AMBIG_NAME;
  1190     case GPG_ERR_ENOMEM:
  1191         return PEP_OUT_OF_MEMORY;
  1192     default:
  1193         assert(0);
  1194         return PEP_UNKNOWN_ERROR;
  1195     }
  1196 
  1197     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1198     gpgme_error = _GPGERR(gpgme_error);
  1199     gpg.gpgme_key_unref(key);
  1200     switch (gpgme_error) {
  1201     case GPG_ERR_NO_ERROR:
  1202         break;
  1203     case GPG_ERR_INV_VALUE:
  1204         assert(0);
  1205         return PEP_UNKNOWN_ERROR;
  1206     case GPG_ERR_NO_PUBKEY:
  1207         assert(0);
  1208         return PEP_KEY_NOT_FOUND;
  1209     case GPG_ERR_AMBIGUOUS_NAME:
  1210         assert(0);
  1211         return PEP_KEY_HAS_AMBIG_NAME;
  1212     default:
  1213         assert(0);
  1214         return PEP_UNKNOWN_ERROR;
  1215     }
  1216 
  1217     return PEP_STATUS_OK;
  1218 }
  1219 
  1220 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1221                               size_t size, identity_list **private_idents)
  1222 {
  1223     gpgme_error_t gpgme_error;
  1224     gpgme_data_t dh;
  1225 
  1226     assert(session);
  1227     assert(key_data);
  1228 
  1229     if(private_idents)
  1230         *private_idents = NULL;
  1231 
  1232     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1233     gpgme_error = _GPGERR(gpgme_error);
  1234     assert(gpgme_error != GPG_ERR_ENOMEM);
  1235     switch (gpgme_error) {
  1236     case GPG_ERR_NO_ERROR:
  1237         break;
  1238     case GPG_ERR_ENOMEM:
  1239         return PEP_OUT_OF_MEMORY;
  1240     case GPG_ERR_INV_VALUE:
  1241         assert(0);
  1242         return PEP_UNKNOWN_ERROR;
  1243     default:
  1244         assert(0);
  1245         return PEP_UNKNOWN_ERROR;
  1246     }
  1247 
  1248     gpgme_import_result_t gpgme_import_result;
  1249 
  1250     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1251     gpgme_error = _GPGERR(gpgme_error);
  1252     switch (gpgme_error) {
  1253     case GPG_ERR_NO_ERROR:
  1254         if(private_idents)
  1255         {
  1256             gpgme_import_result =
  1257                 gpg.gpgme_op_import_result(session->ctx);
  1258             assert(gpgme_import_result);
  1259             if (!gpgme_import_result) {
  1260                 gpg.gpgme_data_release(dh);
  1261                 return PEP_UNKNOWN_ERROR;
  1262             }
  1263 
  1264             gpgme_import_status_t import;
  1265             for (import = gpgme_import_result->imports;
  1266                  import;
  1267                  import = import->next)
  1268              {
  1269                 if (import &&
  1270                     import->result == GPG_ERR_NO_ERROR &&
  1271                     import->status & GPGME_IMPORT_SECRET )
  1272                 {
  1273                     gpgme_key_t key = NULL;
  1274 
  1275                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1276                         import->fpr, &key, 0);
  1277                     gpgme_error = _GPGERR(gpgme_error);
  1278                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1279                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1280                         gpg.gpgme_data_release(dh);
  1281                         return PEP_OUT_OF_MEMORY;
  1282                     }
  1283 
  1284                     if (gpgme_error == GPG_ERR_NO_ERROR &&
  1285                         key && key->uids &&
  1286                         key->uids->email && key->uids->name)
  1287                     {
  1288                         pEp_identity *ident = new_identity(
  1289                              key->uids->email, import->fpr, NULL, key->uids->name);
  1290 
  1291                         gpg.gpgme_key_unref(key);
  1292 
  1293                         if (ident == NULL) {
  1294                             gpg.gpgme_data_release(dh);
  1295                             return PEP_OUT_OF_MEMORY;
  1296                         }
  1297 
  1298                         *private_idents = identity_list_add(*private_idents, ident);
  1299 
  1300                         if (*private_idents == NULL) {
  1301                             gpg.gpgme_data_release(dh);
  1302                             return PEP_OUT_OF_MEMORY;
  1303                         }
  1304                     }
  1305                     else
  1306                     {
  1307                         gpg.gpgme_key_unref(key);
  1308                         gpg.gpgme_data_release(dh);
  1309                         return PEP_UNKNOWN_ERROR;
  1310                     }
  1311                 }
  1312             }
  1313         }
  1314         break;
  1315     case GPG_ERR_INV_VALUE:
  1316         assert(0);
  1317         gpg.gpgme_data_release(dh);
  1318         return PEP_UNKNOWN_ERROR;
  1319     case GPG_ERR_NO_DATA:
  1320         gpg.gpgme_data_release(dh);
  1321         return PEP_ILLEGAL_VALUE;
  1322     default:
  1323         assert(0);
  1324         gpg.gpgme_data_release(dh);
  1325         return PEP_UNKNOWN_ERROR;
  1326     }
  1327 
  1328     gpg.gpgme_data_release(dh);
  1329     return PEP_STATUS_OK;
  1330 }
  1331 
  1332 PEP_STATUS pgp_export_keydata(
  1333         PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
  1334         bool secret
  1335     )
  1336 {
  1337     gpgme_error_t gpgme_error;
  1338     gpgme_data_t dh;
  1339     size_t _size;
  1340     char *buffer;
  1341     int reading;
  1342 
  1343     assert(session);
  1344     assert(fpr);
  1345     assert(key_data);
  1346     assert(size);
  1347 
  1348     gpgme_error = gpg.gpgme_data_new(&dh);
  1349     gpgme_error = _GPGERR(gpgme_error);
  1350     assert(gpgme_error != GPG_ERR_ENOMEM);
  1351     switch (gpgme_error) {
  1352     case GPG_ERR_NO_ERROR:
  1353         break;
  1354     case GPG_ERR_ENOMEM:
  1355         return PEP_OUT_OF_MEMORY;
  1356     case GPG_ERR_INV_VALUE:
  1357         assert(0);
  1358         return PEP_UNKNOWN_ERROR;
  1359     default:
  1360         assert(0);
  1361         return PEP_UNKNOWN_ERROR;
  1362     }
  1363 
  1364     if (secret)
  1365         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1366             GPGME_EXPORT_MODE_SECRET, dh);
  1367     else
  1368         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1369             GPGME_EXPORT_MODE_MINIMAL, dh);
  1370     gpgme_error = _GPGERR(gpgme_error);
  1371     switch (gpgme_error) {
  1372     case GPG_ERR_NO_ERROR:
  1373         break;
  1374     case GPG_ERR_EOF:
  1375         gpg.gpgme_data_release(dh);
  1376         return PEP_KEY_NOT_FOUND;
  1377     case GPG_ERR_INV_VALUE:
  1378         assert(0);
  1379         gpg.gpgme_data_release(dh);
  1380         return PEP_UNKNOWN_ERROR;
  1381     default:
  1382         assert(0);
  1383         gpg.gpgme_data_release(dh);
  1384         return PEP_UNKNOWN_ERROR;
  1385     };
  1386 
  1387     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1388     assert(_size != -1);
  1389     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1390 
  1391     buffer = malloc(_size + 1);
  1392     assert(buffer);
  1393     if (buffer == NULL) {
  1394         gpg.gpgme_data_release(dh);
  1395         return PEP_OUT_OF_MEMORY;
  1396     }
  1397 
  1398     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1399     assert(_size == reading);
  1400     if(_size != reading)
  1401         return PEP_CANNOT_EXPORT_KEY;
  1402 
  1403     // safeguard for the naive user
  1404     buffer[_size] = 0;
  1405 
  1406     *key_data = buffer;
  1407     *size = _size;
  1408 
  1409     gpg.gpgme_data_release(dh);
  1410     return PEP_STATUS_OK;
  1411 }
  1412 
  1413 PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
  1414                             stringpair_list_t** keyinfo_list)
  1415 {
  1416     gpgme_error_t gpgme_error;
  1417     assert(session);
  1418     assert(keyinfo_list);
  1419 
  1420     if (!session || !keyinfo_list)
  1421         return PEP_ILLEGAL_VALUE;
  1422 
  1423     *keyinfo_list = NULL;
  1424 
  1425     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1426     gpgme_error = _GPGERR(gpgme_error);
  1427 
  1428     switch(gpgme_error) {
  1429         case GPG_ERR_NO_ERROR:
  1430             break;
  1431         case GPG_ERR_INV_VALUE:
  1432             assert(0);
  1433             return PEP_UNKNOWN_ERROR;
  1434         default:
  1435             gpg.gpgme_op_keylist_end(session->ctx);
  1436             return PEP_GET_KEY_FAILED;
  1437     };
  1438 
  1439     gpgme_key_t key;
  1440     stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
  1441     stringpair_list_t* list_curr = _keyinfo_list;
  1442     stringpair_t* pair = NULL;
  1443 
  1444     do {
  1445         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1446         gpgme_error = _GPGERR(gpgme_error);
  1447 
  1448         switch(gpgme_error) {
  1449             case GPG_ERR_EOF:
  1450                 break;
  1451             case GPG_ERR_NO_ERROR:
  1452                 assert(key);
  1453                 assert(key->subkeys);
  1454                 if (!key || !key->subkeys)
  1455                     return PEP_GET_KEY_FAILED;
  1456 
  1457                 // first subkey is primary key
  1458                 char* fpr = key->subkeys->fpr;
  1459                 char* uid = key->uids->uid;
  1460 
  1461                 assert(fpr);
  1462                 assert(uid);
  1463                 if (!fpr)
  1464                     return PEP_GET_KEY_FAILED;
  1465 
  1466                 if (key->subkeys->revoked)
  1467                     continue;
  1468 
  1469                 pair = new_stringpair(fpr, uid);
  1470 
  1471                 assert(pair);
  1472 
  1473                 if (pair) {
  1474                     list_curr = stringpair_list_add(list_curr, pair);
  1475                     pair = NULL;
  1476 
  1477                     assert(list_curr);
  1478                     if (list_curr != NULL)
  1479                         break;
  1480                     else
  1481                         free_stringpair(pair);
  1482                 }
  1483                 // else fallthrough (list_curr or pair wasn't allocateable)
  1484             case GPG_ERR_ENOMEM:
  1485                 free_stringpair_list(_keyinfo_list);
  1486                 gpg.gpgme_op_keylist_end(session->ctx);
  1487                 return PEP_OUT_OF_MEMORY;
  1488             default:
  1489                 gpg.gpgme_op_keylist_end(session->ctx);
  1490                 return PEP_UNKNOWN_ERROR;
  1491         }
  1492     } while (gpgme_error != GPG_ERR_EOF);
  1493 
  1494     if (_keyinfo_list->value == NULL) {
  1495         free_stringpair_list(_keyinfo_list);
  1496         _keyinfo_list = NULL;
  1497     }
  1498 
  1499     *keyinfo_list = _keyinfo_list;
  1500 
  1501     return PEP_STATUS_OK;
  1502 }
  1503 
  1504 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1505     gpgme_keylist_mode_t add_mode)
  1506 {
  1507     gpgme_error_t gpgme_error;
  1508     gpgme_keylist_mode_t mode;
  1509 
  1510     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1511 
  1512     mode &= ~remove_mode;
  1513     mode |= add_mode;
  1514 
  1515     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1516     gpgme_error = _GPGERR(gpgme_error);
  1517     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1518 }
  1519 
  1520 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1521 {
  1522     gpgme_error_t gpgme_error;
  1523     gpgme_key_t key;
  1524 
  1525     assert(session);
  1526     assert(pattern);
  1527 
  1528     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1529 
  1530     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1531     gpgme_error = _GPGERR(gpgme_error);
  1532     switch (gpgme_error) {
  1533     case GPG_ERR_NO_ERROR:
  1534         break;
  1535     case GPG_ERR_INV_VALUE:
  1536         assert(0);
  1537         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1538         return PEP_UNKNOWN_ERROR;
  1539     default:
  1540         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1541         return PEP_GET_KEY_FAILED;
  1542     };
  1543 
  1544     gpgme_ctx_t import_ctx;
  1545     gpgme_error = gpg.gpgme_new(&import_ctx);
  1546     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1547 
  1548     do {
  1549         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1550         gpgme_error = _GPGERR(gpgme_error);
  1551         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1552         switch (gpgme_error) {
  1553         case GPG_ERR_EOF:
  1554             break;
  1555         case GPG_ERR_NO_ERROR:
  1556         {
  1557             gpgme_error_t gpgme_error;
  1558             gpgme_key_t keys[2];
  1559 
  1560             keys[0] = key;
  1561             keys[1] = NULL;
  1562 
  1563             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1564             gpgme_error = _GPGERR(gpgme_error);
  1565             gpg.gpgme_key_unref(key);
  1566             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1567             assert(gpgme_error != GPG_ERR_CONFLICT);
  1568         }
  1569             break;
  1570         case GPG_ERR_ENOMEM:
  1571             gpg.gpgme_op_keylist_end(session->ctx);
  1572             gpg.gpgme_release(import_ctx);
  1573             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1574             return PEP_OUT_OF_MEMORY;
  1575         default:
  1576             gpg.gpgme_op_keylist_end(session->ctx);
  1577             gpg.gpgme_release(import_ctx);
  1578             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1579             return PEP_UNKNOWN_ERROR;
  1580         };
  1581     } while (gpgme_error != GPG_ERR_EOF);
  1582 
  1583     gpg.gpgme_op_keylist_end(session->ctx);
  1584     gpg.gpgme_release(import_ctx);
  1585     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1586     return PEP_STATUS_OK;
  1587 }
  1588 
  1589 
  1590 static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
  1591                             stringlist_t** keylist,
  1592                             int private_only) {
  1593     gpgme_error_t gpgme_error;
  1594     gpgme_key_t key;
  1595 
  1596     assert(session);
  1597     assert(keylist);
  1598 
  1599     *keylist = NULL;
  1600 
  1601     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
  1602     gpgme_error = _GPGERR(gpgme_error);
  1603     switch (gpgme_error) {
  1604         case GPG_ERR_NO_ERROR:
  1605             break;
  1606         case GPG_ERR_INV_VALUE:
  1607             assert(0);
  1608             return PEP_UNKNOWN_ERROR;
  1609         default:
  1610             gpg.gpgme_op_keylist_end(session->ctx);
  1611             return PEP_GET_KEY_FAILED;
  1612     };
  1613 
  1614     stringlist_t *_keylist = new_stringlist(NULL);
  1615     stringlist_t *_k = _keylist;
  1616 
  1617     do {
  1618         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1619         gpgme_error = _GPGERR(gpgme_error);
  1620         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1621         switch (gpgme_error) {
  1622             case GPG_ERR_EOF:
  1623                 break;
  1624             case GPG_ERR_NO_ERROR:
  1625                 assert(key);
  1626                 assert(key->subkeys);
  1627                 if(!key->subkeys)
  1628                     break;
  1629                 assert(key->uids);
  1630                 gpgme_user_id_t kuid = key->uids;
  1631                 // check that at least one uid's email matches pattern exactly
  1632                 while(kuid) {
  1633                     if((pattern && kuid->email && strcmp(kuid->email, pattern) == 0) ||
  1634                        pattern == NULL /* match all */ )
  1635                     { 
  1636                         char *fpr = key->subkeys->fpr;
  1637                         assert(fpr);
  1638                         _k = stringlist_add(_k, fpr);
  1639                         assert(_k);
  1640                         if (_k == NULL){
  1641                             free_stringlist(_keylist);
  1642                             gpg.gpgme_op_keylist_end(session->ctx);
  1643                             return PEP_OUT_OF_MEMORY;
  1644                         }
  1645                         break;
  1646                     }
  1647                     kuid = kuid->next;
  1648                 }
  1649                 break;
  1650             case GPG_ERR_ENOMEM:
  1651                 free_stringlist(_keylist);
  1652                 gpg.gpgme_op_keylist_end(session->ctx);
  1653                 return PEP_OUT_OF_MEMORY;
  1654             default:
  1655                 gpg.gpgme_op_keylist_end(session->ctx);
  1656                 return PEP_UNKNOWN_ERROR;
  1657         };
  1658     } while (gpgme_error != GPG_ERR_EOF);
  1659 
  1660     gpg.gpgme_op_keylist_end(session->ctx);
  1661     if (_keylist->value == NULL) {
  1662         free_stringlist(_keylist);
  1663         _keylist = NULL;
  1664     }
  1665     *keylist = _keylist;
  1666     return PEP_STATUS_OK;
  1667 }
  1668 
  1669 PEP_STATUS pgp_find_keys(
  1670     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1671     )
  1672 {
  1673     return _pgp_search_keys(session, pattern, keylist, 0);
  1674 }
  1675 
  1676 PEP_STATUS pgp_find_private_keys(
  1677     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1678 )
  1679 {
  1680     return _pgp_search_keys(session, pattern, keylist, 1);
  1681 }
  1682 
  1683 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1684 {
  1685     gpgme_error_t gpgme_error;
  1686 
  1687     assert(session);
  1688     assert(pattern);
  1689 
  1690     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  1691         GPGME_EXPORT_MODE_EXTERN, NULL);
  1692     gpgme_error = _GPGERR(gpgme_error);
  1693     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1694     if (gpgme_error == GPG_ERR_NO_ERROR)
  1695         return PEP_STATUS_OK;
  1696     else
  1697         return PEP_CANNOT_SEND_KEY;
  1698 }
  1699 
  1700 PEP_STATUS pgp_get_key_rating(
  1701     PEP_SESSION session,
  1702     const char *fpr,
  1703     PEP_comm_type *comm_type
  1704     )
  1705 {
  1706     PEP_STATUS status = PEP_STATUS_OK;
  1707     gpgme_error_t gpgme_error;
  1708     gpgme_key_t key;
  1709 
  1710     assert(session);
  1711     assert(fpr);
  1712     assert(comm_type);
  1713 
  1714     *comm_type = PEP_ct_unknown;
  1715 
  1716     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1717     gpgme_error = _GPGERR(gpgme_error);
  1718     switch (gpgme_error) {
  1719     case GPG_ERR_NO_ERROR:
  1720         break;
  1721     case GPG_ERR_INV_VALUE:
  1722         assert(0);
  1723         return PEP_UNKNOWN_ERROR;
  1724     default:
  1725         return PEP_GET_KEY_FAILED;
  1726     };
  1727 
  1728     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1729     gpgme_error = _GPGERR(gpgme_error);
  1730     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1731 
  1732     if (key == NULL) {
  1733         gpg.gpgme_op_keylist_end(session->ctx);
  1734         return PEP_KEY_NOT_FOUND;
  1735     }
  1736 
  1737     switch (key->protocol) {
  1738     case GPGME_PROTOCOL_OpenPGP:
  1739     case GPGME_PROTOCOL_DEFAULT:
  1740         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1741         break;
  1742     case GPGME_PROTOCOL_CMS:
  1743         *comm_type = PEP_ct_CMS_unconfirmed;
  1744         break;
  1745     default:
  1746         *comm_type = PEP_ct_unknown;
  1747         gpg.gpgme_op_keylist_end(session->ctx);
  1748         return PEP_STATUS_OK;
  1749     }
  1750 
  1751     switch (gpgme_error) {
  1752     case GPG_ERR_EOF:
  1753         break;
  1754     case GPG_ERR_NO_ERROR:
  1755         assert(key);
  1756         assert(key->subkeys);
  1757         for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  1758             if (sk->length < 1024)
  1759                 *comm_type = PEP_ct_key_too_short;
  1760             else if (
  1761                 (
  1762                 (sk->pubkey_algo == GPGME_PK_RSA)
  1763                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  1764                 || (sk->pubkey_algo == GPGME_PK_RSA_S)
  1765                 )
  1766                 && sk->length == 1024
  1767                 )
  1768                 *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1769 
  1770             if (sk->invalid) {
  1771                 *comm_type = PEP_ct_key_b0rken;
  1772                 break;
  1773             }
  1774             if (sk->expired) {
  1775                 *comm_type = PEP_ct_key_expired;
  1776                 break;
  1777             }
  1778             if (sk->revoked) {
  1779                 *comm_type = PEP_ct_key_revoked;
  1780                 break;
  1781             }
  1782         }
  1783         break;
  1784     case GPG_ERR_ENOMEM:
  1785         gpg.gpgme_op_keylist_end(session->ctx);
  1786         *comm_type = PEP_ct_unknown;
  1787         return PEP_OUT_OF_MEMORY;
  1788     default:
  1789         gpg.gpgme_op_keylist_end(session->ctx);
  1790         return PEP_UNKNOWN_ERROR;
  1791     };
  1792 
  1793     gpg.gpgme_op_keylist_end(session->ctx);
  1794 
  1795     return status;
  1796 }
  1797 
  1798 static PEP_STATUS find_single_key(
  1799         PEP_SESSION session,
  1800         const char *fpr,
  1801         gpgme_key_t *key
  1802     )
  1803 {
  1804     gpgme_error_t gpgme_error;
  1805 
  1806     *key = NULL;
  1807 
  1808     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1809     gpgme_error = _GPGERR(gpgme_error);
  1810     switch (gpgme_error) {
  1811     case GPG_ERR_NO_ERROR:
  1812         break;
  1813     case GPG_ERR_INV_VALUE:
  1814         assert(0);
  1815         return PEP_UNKNOWN_ERROR;
  1816     default:
  1817         return PEP_GET_KEY_FAILED;
  1818     };
  1819 
  1820     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1821     gpgme_error = _GPGERR(gpgme_error);
  1822     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1823 
  1824     gpg.gpgme_op_keylist_end(session->ctx);
  1825 
  1826     return PEP_STATUS_OK;
  1827 }
  1828 
  1829 typedef struct _renew_state {
  1830     enum {
  1831         renew_command = 0,
  1832         renew_date,
  1833         renew_secret_key,
  1834         renew_command2,
  1835         renew_date2,
  1836         renew_quit,
  1837         renew_save,
  1838         renew_exit,
  1839         renew_error = -1
  1840     } state;
  1841     const char *date_ref;
  1842 } renew_state;
  1843 
  1844 static gpgme_error_t renew_fsm(
  1845         void *_handle,
  1846         gpgme_status_code_t statuscode,
  1847         const char *args,
  1848         int fd
  1849     )
  1850 {
  1851     renew_state *handle = _handle;
  1852 
  1853     switch (handle->state) {
  1854         case renew_command:
  1855             if (statuscode == GPGME_STATUS_GET_LINE) {
  1856                 assert(strcmp(args, "keyedit.prompt") == 0);
  1857                 if (strcmp(args, "keyedit.prompt")) {
  1858                     handle->state = renew_error;
  1859                     return GPG_ERR_GENERAL;
  1860                 }
  1861                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1862                 handle->state = renew_date;
  1863             }
  1864             break;
  1865 
  1866         case renew_date:
  1867             if (statuscode == GPGME_STATUS_GET_LINE) {
  1868                 assert(strcmp(args, "keygen.valid") == 0);
  1869                 if (strcmp(args, "keygen.valid")) {
  1870                     handle->state = renew_error;
  1871                     return GPG_ERR_GENERAL;
  1872                 }
  1873                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1874                 handle->state = renew_secret_key;
  1875             }
  1876             break;
  1877 
  1878         case renew_secret_key:
  1879             if (statuscode == GPGME_STATUS_GET_LINE) {
  1880                 assert(strcmp(args, "keyedit.prompt") == 0);
  1881                 if (strcmp(args, "keyedit.prompt")) {
  1882                     handle->state = renew_error;
  1883                     return GPG_ERR_GENERAL;
  1884                 }
  1885                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  1886                 handle->state = renew_command2;
  1887             }
  1888             break;
  1889 
  1890         case renew_command2:
  1891             if (statuscode == GPGME_STATUS_GET_LINE) {
  1892                 assert(strcmp(args, "keyedit.prompt") == 0);
  1893                 if (strcmp(args, "keyedit.prompt")) {
  1894                     handle->state = renew_error;
  1895                     return GPG_ERR_GENERAL;
  1896                 }
  1897                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1898                 handle->state = renew_date2;
  1899             }
  1900             break;
  1901 
  1902         case renew_date2:
  1903             if (statuscode == GPGME_STATUS_GET_LINE) {
  1904                 assert(strcmp(args, "keygen.valid") == 0);
  1905                 if (strcmp(args, "keygen.valid")) {
  1906                     handle->state = renew_error;
  1907                     return GPG_ERR_GENERAL;
  1908                 }
  1909                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1910                 handle->state = renew_quit;
  1911             }
  1912             break;
  1913 
  1914         case renew_quit:
  1915             if (statuscode == GPGME_STATUS_GET_LINE) {
  1916                 assert(strcmp(args, "keyedit.prompt") == 0);
  1917                 if (strcmp(args, "keyedit.prompt")) {
  1918                     handle->state = renew_error;
  1919                     return GPG_ERR_GENERAL;
  1920                 }
  1921                 gpg.gpgme_io_write(fd, "quit\n", 5);
  1922                 handle->state = renew_save;
  1923             }
  1924             break;
  1925 
  1926         case renew_save:
  1927             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1928                 assert(strcmp(args, "keyedit.save.okay") == 0);
  1929                 if (strcmp(args, "keyedit.save.okay")) {
  1930                     handle->state = renew_error;
  1931                     return GPG_ERR_GENERAL;
  1932                 }
  1933                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1934                 handle->state = renew_exit;
  1935             }
  1936             break;
  1937 
  1938         case renew_exit:
  1939             break;
  1940 
  1941         case renew_error:
  1942             return GPG_ERR_GENERAL;
  1943     }
  1944 
  1945     return GPG_ERR_NO_ERROR;
  1946 }
  1947 
  1948 static ssize_t _nullwriter(
  1949         void *_handle,
  1950         const void *buffer,
  1951         size_t size
  1952     )
  1953 {
  1954     return size;
  1955 }
  1956 
  1957 PEP_STATUS pgp_renew_key(
  1958         PEP_SESSION session,
  1959         const char *fpr,
  1960         const timestamp *ts
  1961     )
  1962 {
  1963     PEP_STATUS status = PEP_STATUS_OK;
  1964     gpgme_error_t gpgme_error;
  1965     gpgme_key_t key;
  1966     gpgme_data_t output;
  1967     renew_state handle;
  1968     char date_text[12];
  1969 
  1970     assert(session);
  1971     assert(fpr);
  1972 
  1973     memset(&handle, 0, sizeof(renew_state));
  1974     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  1975             ts->tm_mon + 1, ts->tm_mday);
  1976     handle.date_ref = date_text;
  1977 
  1978     status = find_single_key(session, fpr, &key);
  1979     if (status != PEP_STATUS_OK)
  1980         return status;
  1981 
  1982     struct gpgme_data_cbs data_cbs;
  1983     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  1984     data_cbs.write = _nullwriter;
  1985     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  1986 
  1987     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  1988             output);
  1989     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1990     if(gpgme_error != GPG_ERR_NO_ERROR) {
  1991         status = PEP_CANNOT_EDIT_KEY;
  1992     }
  1993 
  1994     gpg.gpgme_data_release(output);
  1995     gpg.gpgme_key_unref(key);
  1996 
  1997     return status;
  1998 }
  1999 
  2000 typedef struct _revoke_state {
  2001     enum {
  2002         revoke_command = 0,
  2003         revoke_approve,
  2004         revoke_reason_code,
  2005         revoke_reason_text,
  2006         revoke_reason_ok,
  2007         revoke_quit,
  2008         revoke_save,
  2009         revoke_exit,
  2010         revoke_error = -1
  2011     } state;
  2012     const char *reason_ref;
  2013 } revoke_state;
  2014 
  2015 
  2016 /*** unused?
  2017 static bool isemptystring(const char *str)
  2018 {
  2019     if (str == NULL)
  2020         return true;
  2021 
  2022     for (; str; str++) {
  2023         if (*str != ' ' && *str != '\t' && *str != '\n')
  2024             return false;
  2025     }
  2026 
  2027     return true;
  2028 }
  2029 ***/
  2030 
  2031 
  2032 static gpgme_error_t revoke_fsm(
  2033         void *_handle,
  2034         gpgme_status_code_t statuscode,
  2035         const char *args,
  2036         int fd
  2037     )
  2038 {
  2039     revoke_state *handle = _handle;
  2040 
  2041     switch (handle->state) {
  2042         case revoke_command:
  2043             if (statuscode == GPGME_STATUS_GET_LINE) {
  2044                 assert(strcmp(args, "keyedit.prompt") == 0);
  2045                 if (strcmp(args, "keyedit.prompt")) {
  2046                     handle->state = revoke_error;
  2047                     return GPG_ERR_GENERAL;
  2048                 }
  2049                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  2050                 handle->state = revoke_approve;
  2051             }
  2052             break;
  2053 
  2054         case revoke_approve:
  2055             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2056                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  2057                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  2058                     handle->state = revoke_error;
  2059                     return GPG_ERR_GENERAL;
  2060                 }
  2061                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2062                 handle->state = revoke_reason_code;
  2063             }
  2064             break;
  2065 
  2066         case revoke_reason_code:
  2067             if (statuscode == GPGME_STATUS_GET_LINE) {
  2068                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  2069                 if (strcmp(args, "ask_revocation_reason.code")) {
  2070                     handle->state = revoke_error;
  2071                     return GPG_ERR_GENERAL;
  2072                 }
  2073                 gpg.gpgme_io_write(fd, "1\n", 2);
  2074                 handle->state = revoke_reason_text;
  2075             }
  2076             break;
  2077 
  2078         case revoke_reason_text:
  2079             if (statuscode == GPGME_STATUS_GET_LINE) {
  2080                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  2081                 if (strcmp(args, "ask_revocation_reason.text")) {
  2082                     handle->state = revoke_error;
  2083                     return GPG_ERR_GENERAL;
  2084                 }
  2085                 // BUG: issues when reason given
  2086                 // Assertion failed: (gpg->cmd.code), function command_handler,
  2087                 // file engine-gpg.c, line 662.
  2088                 //
  2089                 // if (isemptystring(handle->reason_ref)) {
  2090                     gpg.gpgme_io_write(fd, "\n", 1);
  2091                 // }
  2092                 // else {
  2093                 //     size_t len = strlen(handle->reason_ref);
  2094                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  2095                 //     if (handle->reason_ref[len - 1] == '\n')
  2096                 //         gpg.gpgme_io_write(fd, "\n", 1);
  2097                 //     else
  2098                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  2099                 // }
  2100                 handle->state = revoke_reason_ok;
  2101             }
  2102             break;
  2103 
  2104         case revoke_reason_ok:
  2105             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2106                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  2107                 if (strcmp(args, "ask_revocation_reason.okay")) {
  2108                     handle->state = revoke_error;
  2109                     return GPG_ERR_GENERAL;
  2110                 }
  2111                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2112                 handle->state = revoke_quit;
  2113             }
  2114             break;
  2115 
  2116         case revoke_quit:
  2117             if (statuscode == GPGME_STATUS_GET_LINE) {
  2118                 assert(strcmp(args, "keyedit.prompt") == 0);
  2119                 if (strcmp(args, "keyedit.prompt")) {
  2120                     handle->state = revoke_error;
  2121                     return GPG_ERR_GENERAL;
  2122                 }
  2123                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2124                 handle->state = revoke_save;
  2125             }
  2126             break;
  2127 
  2128         case revoke_save:
  2129             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2130                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2131                 if (strcmp(args, "keyedit.save.okay")) {
  2132                     handle->state = revoke_error;
  2133                     return GPG_ERR_GENERAL;
  2134                 }
  2135                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2136                 handle->state = revoke_exit;
  2137             }
  2138             break;
  2139 
  2140         case revoke_exit:
  2141             break;
  2142 
  2143         case revoke_error:
  2144             return GPG_ERR_GENERAL;
  2145     }
  2146 
  2147     return GPG_ERR_NO_ERROR;
  2148 }
  2149 
  2150 PEP_STATUS pgp_revoke_key(
  2151         PEP_SESSION session,
  2152         const char *fpr,
  2153         const char *reason
  2154     )
  2155 {
  2156     PEP_STATUS status = PEP_STATUS_OK;
  2157     gpgme_error_t gpgme_error;
  2158     gpgme_key_t key;
  2159     gpgme_data_t output;
  2160     revoke_state handle;
  2161 
  2162     assert(session);
  2163     assert(fpr);
  2164 
  2165     memset(&handle, 0, sizeof(revoke_state));
  2166     handle.reason_ref = reason;
  2167 
  2168     status = find_single_key(session, fpr, &key);
  2169     if (status != PEP_STATUS_OK)
  2170         return status;
  2171 
  2172     struct gpgme_data_cbs data_cbs;
  2173     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2174     data_cbs.write = _nullwriter;
  2175     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2176 
  2177     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  2178             output);
  2179     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2180     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2181         status = PEP_CANNOT_EDIT_KEY;
  2182     }
  2183 
  2184     gpg.gpgme_data_release(output);
  2185     gpg.gpgme_key_unref(key);
  2186 
  2187     return status;
  2188 }
  2189 
  2190 PEP_STATUS pgp_key_expired(
  2191         PEP_SESSION session,
  2192         const char *fpr,
  2193         const time_t when,
  2194         bool *expired
  2195     )
  2196 {
  2197     PEP_STATUS status = PEP_STATUS_OK;
  2198     gpgme_key_t key;
  2199 
  2200     assert(session);
  2201     assert(fpr);
  2202     assert(expired);
  2203 
  2204     *expired = false;
  2205 
  2206     status = find_single_key(session, fpr, &key);
  2207     if (status != PEP_STATUS_OK)
  2208         return status;
  2209 
  2210     if ((key && key->expired) ||
  2211         (key && key->subkeys && key->subkeys->expired))
  2212     {
  2213         // Already marked expired
  2214         *expired = 1;
  2215     }
  2216     else if (key)
  2217     {
  2218         // Detect if will be expired
  2219         // i.e. Check that keys capabilities will
  2220         // not be expired at given time.
  2221         gpgme_subkey_t _sk;
  2222         bool crt_available = false;
  2223         bool sgn_available = false;
  2224         bool enc_available = false;
  2225         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  2226             if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
  2227                                                           // Also, zero means "does not expire"
  2228             {
  2229                 if (_sk->can_certify) crt_available = true;
  2230                 if (_sk->can_sign) sgn_available = true;
  2231                 if (_sk->can_encrypt) enc_available = true;
  2232                 // Authenticate is not used here.
  2233             }
  2234         }
  2235         if(!(crt_available && sgn_available && enc_available))
  2236         {
  2237             *expired = 1;
  2238         }
  2239     }
  2240     else
  2241     {
  2242         status = PEP_KEY_NOT_FOUND;
  2243     }
  2244 
  2245     gpg.gpgme_key_unref(key);
  2246     return status;
  2247 }
  2248 
  2249 PEP_STATUS pgp_key_revoked(
  2250         PEP_SESSION session,
  2251         const char *fpr,
  2252         bool *revoked
  2253     )
  2254 {
  2255     PEP_STATUS status = PEP_STATUS_OK;
  2256     gpgme_key_t key;
  2257 
  2258     assert(session);
  2259     assert(fpr);
  2260     assert(revoked);
  2261 
  2262     *revoked = false;
  2263 
  2264     status = find_single_key(session, fpr, &key);
  2265     if (status != PEP_STATUS_OK)
  2266         return status;
  2267 
  2268     if (key && key->subkeys)
  2269     {
  2270         *revoked = key->subkeys->revoked;
  2271     }
  2272     else
  2273     {
  2274         status = PEP_KEY_NOT_FOUND;
  2275     }
  2276 
  2277     gpg.gpgme_key_unref(key);
  2278     return status;
  2279 }
  2280 
  2281 PEP_STATUS pgp_key_created(
  2282         PEP_SESSION session,
  2283         const char *fpr,
  2284         time_t *created
  2285     )
  2286 {
  2287     PEP_STATUS status = PEP_STATUS_OK;
  2288     gpgme_key_t key;
  2289 
  2290     assert(session);
  2291     assert(fpr);
  2292     assert(created);
  2293 
  2294     *created = 0;
  2295 
  2296     status = find_single_key(session, fpr, &key);
  2297     if (status != PEP_STATUS_OK)
  2298         return status;
  2299 
  2300     if (key && key->subkeys)
  2301     {
  2302         *created = (time_t) key->subkeys->timestamp;
  2303     }
  2304     else
  2305     {
  2306         status = PEP_KEY_NOT_FOUND;
  2307     }
  2308 
  2309     gpg.gpgme_key_unref(key);
  2310     return status;
  2311 }
  2312 
  2313 PEP_STATUS pgp_binary(const char **path)
  2314 {
  2315     assert(path);
  2316     if (path == NULL)
  2317         return PEP_ILLEGAL_VALUE;
  2318 
  2319     *path = NULL;
  2320 
  2321     gpgme_engine_info_t info;
  2322     int err = gpg.gpgme_get_engine_info(&info);
  2323     assert(err == GPG_ERR_NO_ERROR);
  2324     if (err != GPG_ERR_NO_ERROR)
  2325         return PEP_OUT_OF_MEMORY;
  2326 
  2327     *path = info->file_name;
  2328 
  2329     return PEP_STATUS_OK;
  2330 }
  2331 
  2332 PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
  2333         bool *has_private) {
  2334     PEP_STATUS status = PEP_STATUS_OK;
  2335     gpgme_key_t output_key;
  2336     gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
  2337     *has_private = false;
  2338     switch (gpgerr) {
  2339         case GPG_ERR_EOF:
  2340         case GPG_ERR_INV_VALUE:
  2341             status = PEP_KEY_NOT_FOUND;
  2342             break;
  2343         case GPG_ERR_AMBIGUOUS_NAME:
  2344             status = PEP_KEY_HAS_AMBIG_NAME;
  2345             break;
  2346         case GPG_ERR_NO_ERROR:
  2347             *has_private = true;
  2348             gpg.gpgme_key_release(output_key);
  2349             break;
  2350         case GPG_ERR_ENOMEM:
  2351             status = PEP_OUT_OF_MEMORY;
  2352             break;
  2353         default:
  2354             status = PEP_UNKNOWN_ERROR;
  2355             break;
  2356     }
  2357     return status;
  2358 }