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