src/pgp_gpg.c
author Volker Birk <vb@pep-project.org>
Fri, 27 Mar 2020 09:24:14 +0100
branchgenerate_api
changeset 4509 57c3b0e60ecf
parent 4242 813d4d700713
permissions -rw-r--r--
...
     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 #ifdef NODLSYM
    15 #define DLOAD(X) gpg.X = X
    16 #else
    17 #define DLOAD(X) gpg.X = (X ## _t) (intptr_t) dlsym(gpgme, #X); assert(gpg.X)
    18 #endif
    19 
    20 static void *gpgme;
    21 static struct gpg_s gpg;
    22 
    23 static bool ensure_config_values(stringlist_t *keys, stringlist_t *values, const char* config_file_path)
    24 {
    25     int r;
    26     stringlist_t *_k;
    27     stringlist_t *_v;
    28     unsigned int i;
    29     unsigned int found = 0;
    30     bool eof_nl = 0;
    31     char * rest = NULL;
    32     const char* line_end;
    33 
    34 #ifdef WIN32
    35     line_end = "\r\n";
    36 #else
    37     line_end = "\n";
    38 #endif    
    39 
    40     FILE *f = Fopen(config_file_path, "r");
    41     if (f == NULL && errno == ENOMEM)
    42         return false;
    43 
    44     if (f != NULL) {
    45         static char buf[MAX_LINELENGTH];
    46         int length = stringlist_length(keys);
    47         char * s;
    48 
    49         // make sure we 1) have the same number of keys and values
    50         // and 2) we don't have more key/value pairs than
    51         // the size of the bitfield used to hold the indices
    52         // of key/value pairs matching keys in the config file.
    53         assert(length <= sizeof(unsigned int) * CHAR_BIT);
    54         assert(length == stringlist_length(values));
    55         if (!(length == stringlist_length(values) &&
    56               length <= sizeof(unsigned int) * CHAR_BIT)) {
    57             Fclose(f);
    58 
    59             return false;
    60         }
    61 
    62         while ((s = Fgets(buf, MAX_LINELENGTH, f))) {
    63             char *token = strtok_r(s, " \t\r\n", &rest);
    64             for (_k = keys, _v = values, i = 1;
    65                  _k != NULL;
    66                  _k = _k->next, _v = _v->next, i <<= 1) {
    67 
    68                 if (((found & i) != i) && token &&
    69                     (strncmp(token, _k->value, strlen(_k->value)) == 0)) {
    70                     found |= i;
    71                     break;
    72                 }
    73             }
    74             if (feof(f)) {
    75                 eof_nl = 1;
    76                 break;
    77             }
    78         }
    79 
    80         if (!s && ferror(f))
    81             return false;
    82         f = Freopen(config_file_path, "a", f);
    83     }
    84     else {
    85         f = Fopen(config_file_path, "w");
    86     }
    87 
    88     assert(f);
    89     if (f == NULL)
    90         return false;
    91     
    92     if (eof_nl)
    93         r = Fprintf(f, line_end);
    94 
    95     for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
    96             _v = _v->next, i <<= 1) {
    97         if ((found & i) == 0) {
    98             r = Fprintf(f, "%s %s%s", _k->value, _v->value, line_end);
    99             assert(r >= 0);
   100             if (r < 0)
   101                 return false;
   102         }
   103     }
   104 
   105     r = Fclose(f);
   106     assert(r == 0);
   107     if (r != 0)
   108         return false;
   109 
   110     return true;
   111 }
   112 
   113 char* _undot_address(const char* address) {
   114     if (!address)
   115         return NULL;
   116     
   117     int addr_len = strlen(address);
   118     const char* at = strstr(address, "@");
   119     
   120     if (!at)
   121         at = address + addr_len;
   122         
   123     char* retval = calloc(1, addr_len + 1);
   124     assert(retval);
   125     if (!retval)
   126         return NULL;
   127 
   128     const char* addr_curr = address;
   129     char* retval_curr = retval;
   130     
   131     while (addr_curr < at) {
   132         if (*addr_curr == '.') {
   133             addr_curr++;
   134             continue;
   135         }
   136         *retval_curr = *addr_curr;
   137         retval_curr++;
   138         addr_curr++;
   139     }
   140     if (*addr_curr == '@')
   141         strcat(retval_curr, addr_curr);
   142     
   143     return retval;
   144 }
   145 
   146 static bool _email_heuristic_match(const char* str1, const char* str2) {
   147     if (!str1 || !str2)
   148         return false;
   149         
   150     if (strcasecmp(str1, str2) == 0)
   151         return true;
   152     
   153     int len1 = strlen(str1);
   154     int len2 = strlen(str2);
   155     
   156     // otherwise, we work against dotted usernames
   157     const char* at1 = strstr(str1, "@");
   158     const char* at2 = strstr(str2, "@");
   159     
   160     if (!at1)
   161         at1 = str1 + len1;
   162     
   163     if (!at2)
   164         at2 = str2 + len2;
   165         
   166     // This sucks. And is expensive. Here we go.
   167     const char* str1_curr = str1;
   168     const char* str2_curr = str2;
   169     
   170     while (str1_curr > at1 && str2_curr > at2) {
   171         if (*str1_curr == '.') {
   172             str1_curr++;
   173             continue;
   174         }
   175 
   176         if (*str2_curr == '.') {
   177             str2_curr++;
   178             continue;
   179         }
   180         
   181         if (tolower(*str1_curr) != tolower(*str2_curr))
   182             return false;
   183         
   184         str1_curr++;
   185         str2_curr++;
   186     }
   187     if (str1_curr == at1 && str2_curr == at2)
   188         return true;
   189     
   190     return false;
   191 }
   192 
   193 static PEP_STATUS _version_test(const char *s)
   194 {
   195     char *_s = strdup(s);
   196     if (!_s)
   197         return PEP_OUT_OF_MEMORY;
   198 
   199     int major;
   200     int minor;
   201     int revision;
   202 
   203     char *lasts = NULL;
   204     char *p = strtok_r(_s, ".", &lasts);
   205     if (!p)
   206         goto unsupported;
   207     else
   208         major = atoi(p);
   209 
   210     p = strtok_r(NULL, ".", &lasts);
   211     if (!p)
   212         goto unsupported;
   213     else
   214         minor = atoi(p);
   215 
   216     p = strtok_r(NULL, ".", &lasts);
   217     if (!p)
   218         goto unsupported;
   219     else
   220         revision = atoi(p);
   221 
   222     free(_s);
   223     _s = NULL;
   224 
   225     if (major > 2)
   226         return PEP_STATUS_OK;
   227 
   228     if (major == 2 && minor > 1)
   229         return PEP_STATUS_OK;
   230 
   231     if (major == 2 && minor == 0 && revision == 30)
   232         return PEP_STATUS_OK;
   233 
   234     if (major == 2 && minor == 1 && revision >= 17)
   235         return PEP_STATUS_OK;
   236 
   237 unsupported:
   238     free(_s);
   239     return PEP_INIT_UNSUPPORTED_GPG_VERSION;
   240 }
   241 
   242 PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   243 {
   244     PEP_STATUS status = PEP_STATUS_OK;
   245     gpgme_error_t gpgme_error;
   246     bool bResult;
   247 
   248     if (in_first) {
   249         stringlist_t *conf_keys   = new_stringlist("keyserver");
   250         stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
   251 
   252         stringlist_add(conf_keys, "cert-digest-algo");
   253         stringlist_add(conf_values, "SHA256");
   254 
   255         stringlist_add(conf_keys, "no-emit-version");
   256         stringlist_add(conf_values, "");
   257 
   258         stringlist_add(conf_keys, "no-comments");
   259         stringlist_add(conf_values, "");
   260 
   261         stringlist_add(conf_keys, "personal-cipher-preferences");
   262         stringlist_add(conf_values, "AES AES256 AES192 CAST5");
   263 
   264         stringlist_add(conf_keys, "personal-digest-preferences");
   265         stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
   266 
   267         stringlist_add(conf_keys, "ignore-time-conflict");
   268         stringlist_add(conf_values, "");
   269 
   270         stringlist_add(conf_keys, "allow-freeform-uid");
   271         stringlist_add(conf_values, "");
   272 
   273 #if defined(WIN32) || defined(NDEBUG)
   274         bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
   275 #else
   276         bResult = ensure_config_values(conf_keys, conf_values, gpg_conf(false));
   277 #endif
   278         free_stringlist(conf_keys);
   279         free_stringlist(conf_values);
   280 
   281         assert(bResult);
   282         if (!bResult) {
   283             status = PEP_INIT_NO_GPG_HOME;
   284             goto pEp_error;
   285         }
   286 
   287         conf_keys = new_stringlist("default-cache-ttl");
   288         conf_values = new_stringlist("300");
   289 
   290         stringlist_add(conf_keys, "max-cache-ttl");
   291         stringlist_add(conf_values, "1200");
   292 
   293 #if defined(WIN32) || defined(NDEBUG)
   294         bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf());
   295 #else        
   296         bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf(false));
   297 #endif
   298         free_stringlist(conf_keys);
   299         free_stringlist(conf_values);
   300 
   301         assert(bResult);
   302         if (!bResult) {
   303             status = PEP_INIT_CANNOT_CONFIG_GPG_AGENT;
   304             goto pEp_error;
   305         }
   306 
   307 #ifndef NODLSYM
   308         gpgme = dlopen(LIBGPGME, RTLD_LAZY);
   309         if (gpgme == NULL) {
   310             status = PEP_INIT_CANNOT_LOAD_GPGME;
   311             goto pEp_error;
   312         }
   313 #endif
   314 
   315         memset(&gpg, 0, sizeof(struct gpg_s));
   316 
   317         DLOAD(gpgme_get_engine_info);
   318 
   319         gpgme_engine_info_t info;
   320         int err = gpg.gpgme_get_engine_info(&info);
   321         assert(err == GPG_ERR_NO_ERROR);
   322         if (err != GPG_ERR_NO_ERROR)
   323             return PEP_OUT_OF_MEMORY;
   324 
   325         assert(info->version);
   326         if (!info->version)
   327             return PEP_INIT_CANNOT_DETERMINE_GPG_VERSION;
   328 
   329         status = _version_test(info->version);
   330         if (status != PEP_STATUS_OK)
   331             return status;
   332 
   333 #ifdef NODLSYM
   334         gpg.gpgme_check = gpgme_check_version;
   335 #else
   336         gpg.gpgme_check = (gpgme_check_t) (intptr_t) dlsym(gpgme, "gpgme_check_version");
   337         assert(gpg.gpgme_check);
   338 #endif
   339 
   340         DLOAD(gpgme_set_locale);
   341         DLOAD(gpgme_new);
   342         DLOAD(gpgme_release);
   343         DLOAD(gpgme_set_protocol);
   344         DLOAD(gpgme_set_armor);
   345         DLOAD(gpgme_data_new);
   346         DLOAD(gpgme_data_new_from_mem);
   347         DLOAD(gpgme_data_new_from_cbs);
   348         DLOAD(gpgme_data_release);
   349         DLOAD(gpgme_data_identify);
   350         DLOAD(gpgme_data_seek);
   351         DLOAD(gpgme_data_read);
   352         DLOAD(gpgme_op_decrypt);
   353         DLOAD(gpgme_op_verify);
   354         DLOAD(gpgme_op_decrypt_verify);
   355         DLOAD(gpgme_op_decrypt_result);
   356         DLOAD(gpgme_op_encrypt_sign);
   357         DLOAD(gpgme_op_encrypt);
   358         DLOAD(gpgme_op_sign);
   359         DLOAD(gpgme_op_verify_result);
   360         DLOAD(gpgme_signers_clear);
   361         DLOAD(gpgme_signers_add);
   362         DLOAD(gpgme_set_passphrase_cb);
   363         DLOAD(gpgme_get_key);
   364         DLOAD(gpgme_strerror);
   365         
   366 #ifdef GPGME_VERSION_NUMBER
   367 #if (GPGME_VERSION_NUMBER >= 0x010700)
   368         DLOAD(gpgme_op_createkey);
   369         DLOAD(gpgme_op_createsubkey);
   370 #endif
   371 #endif
   372 
   373         DLOAD(gpgme_op_genkey);
   374         DLOAD(gpgme_op_genkey_result);
   375         DLOAD(gpgme_op_delete);
   376         DLOAD(gpgme_op_import);
   377         DLOAD(gpgme_op_import_result);
   378         DLOAD(gpgme_op_export);
   379         DLOAD(gpgme_set_keylist_mode);
   380         DLOAD(gpgme_get_keylist_mode);
   381         DLOAD(gpgme_op_keylist_start);
   382         DLOAD(gpgme_op_keylist_next);
   383         DLOAD(gpgme_op_keylist_end);
   384         DLOAD(gpgme_op_import_keys);
   385         DLOAD(gpgme_key_ref);
   386         DLOAD(gpgme_key_unref);
   387 		DLOAD(gpgme_key_release);
   388         DLOAD(gpgme_op_edit);
   389         DLOAD(gpgme_io_write);
   390 
   391         gpg.version = gpg.gpgme_check(NULL);
   392 
   393         const char * const cLocal = setlocale(LC_ALL, NULL);
   394         if (!cLocal || (strcmp(cLocal, "C") == 0))
   395             setlocale(LC_ALL, "");
   396 
   397         gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
   398 #ifdef LC_MESSAGES // Windoze
   399         gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
   400 #endif
   401     }
   402 
   403     gpg.gpgme_check(NULL);
   404     gpgme_error = gpg.gpgme_new(&session->ctx);
   405     gpgme_error = _GPGERR(gpgme_error);
   406     if (gpgme_error != GPG_ERR_NO_ERROR) {
   407         status = PEP_INIT_GPGME_INIT_FAILED;
   408         goto pEp_error;
   409     }
   410     assert(session->ctx);
   411 
   412     gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
   413     gpgme_error = _GPGERR(gpgme_error);
   414     assert(gpgme_error == GPG_ERR_NO_ERROR);
   415 
   416     gpg.gpgme_set_armor(session->ctx, 1);
   417 
   418     return PEP_STATUS_OK;
   419 
   420 pEp_error:
   421     pgp_release(session, in_first);
   422     return status;
   423 }
   424 
   425 void pgp_release(PEP_SESSION session, bool out_last)
   426 {
   427     if (session->ctx) {
   428         gpg.gpgme_release(session->ctx);
   429         session->ctx = NULL;
   430     }
   431 
   432     if (out_last)
   433         if (gpgme)
   434             dlclose(gpgme);
   435 }
   436 
   437 PEP_STATUS pgp_decrypt_and_verify(
   438     PEP_SESSION session, const char *ctext, size_t csize,
   439     const char *dsigtext, size_t dsigsize,
   440     char **ptext, size_t *psize, stringlist_t **keylist,
   441     char** filename_ptr
   442     )
   443 {
   444     PEP_STATUS result;
   445     gpgme_error_t gpgme_error;
   446     gpgme_data_t cipher, plain;
   447     gpgme_data_type_t dt;
   448     gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
   449 
   450     stringlist_t *_keylist = NULL;
   451     //int i_key = 0;
   452 
   453     assert(session);
   454     assert(ctext);
   455     assert(csize);
   456     assert(ptext);
   457     assert(psize);
   458     assert(keylist);
   459 
   460     *ptext = NULL;
   461     *psize = 0;
   462     *keylist = NULL;
   463 
   464     gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
   465     gpgme_error = _GPGERR(gpgme_error);
   466     assert(gpgme_error == GPG_ERR_NO_ERROR);
   467     if (gpgme_error != GPG_ERR_NO_ERROR) {
   468         if (gpgme_error == GPG_ERR_ENOMEM)
   469             return PEP_OUT_OF_MEMORY;
   470         else
   471             return PEP_UNKNOWN_ERROR;
   472     }
   473 
   474     gpgme_error = gpg.gpgme_data_new(&plain);
   475     gpgme_error = _GPGERR(gpgme_error);
   476     assert(gpgme_error == GPG_ERR_NO_ERROR);
   477     if (gpgme_error != GPG_ERR_NO_ERROR) {
   478         gpg.gpgme_data_release(cipher);
   479         if (gpgme_error == GPG_ERR_ENOMEM)
   480             return PEP_OUT_OF_MEMORY;
   481         else
   482             return PEP_UNKNOWN_ERROR;
   483     }
   484 
   485 
   486     dt = gpg.gpgme_data_identify(cipher);
   487     switch (dt) {
   488 #if GPGME_VERSION_NUMBER > 0x010600
   489     case GPGME_DATA_TYPE_PGP_ENCRYPTED:
   490 #endif
   491     case GPGME_DATA_TYPE_PGP_SIGNED:
   492     case GPGME_DATA_TYPE_PGP_OTHER:
   493         if (dsigtext) {
   494             gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
   495         }
   496         else {
   497             gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
   498                 plain);
   499         }
   500         gpgme_error = _GPGERR(gpgme_error);
   501         assert(gpgme_error != GPG_ERR_INV_VALUE);
   502 //        assert(gpgme_error != GPG_ERR_NO_DATA);
   503 
   504         switch (gpgme_error) {
   505             case GPG_ERR_NO_ERROR:
   506             {
   507                 // EFail: We should get an MDC warning if there were modifications
   508                 //        and never make it here. So the decrypted text is not
   509                 //        returned regardless.
   510                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   511                 /* NOW is when we have to process the decrypt_result, period.
   512                    it is only valid until the next call on the context. */
   513                    
   514                 gpgme_key_t key;
   515                 memset(&key,0,sizeof(key));
   516                 stringlist_t* recipient_keylist = new_stringlist(NULL);
   517                 if (!recipient_keylist) {
   518                     gpg.gpgme_data_release(plain);
   519                     gpg.gpgme_data_release(cipher);
   520                     return PEP_OUT_OF_MEMORY;
   521                 }
   522                
   523                 if (gpgme_decrypt_result != NULL) {
   524                     stringlist_t* _keylist = recipient_keylist;
   525                     for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   526                         // GPGME may give subkey's fpr instead of primary key's fpr.
   527                         // Therefore we ask for the primary fingerprint instead
   528                         // we assume that gpgme_get_key can find key by subkey's fpr
   529                         gpgme_error = gpg.gpgme_get_key(session->ctx,
   530                             r->keyid, &key, 0);
   531                         gpgme_error = _GPGERR(gpgme_error);
   532                         assert(gpgme_error != GPG_ERR_ENOMEM);
   533                         if (gpgme_error == GPG_ERR_ENOMEM) {
   534                             free_stringlist(_keylist);
   535                             result = PEP_OUT_OF_MEMORY;
   536                         }
   537                         // Primary key is given as the first subkey
   538                         if (gpgme_error == GPG_ERR_NO_ERROR &&
   539                             key && key->subkeys && key->subkeys->fpr
   540                             && key->subkeys->fpr[0]) {
   541                             _keylist = stringlist_add(_keylist, key->subkeys->fpr);
   542  
   543                             gpg.gpgme_key_unref(key);
   544  
   545                         }
   546                     }
   547                     assert(_keylist);
   548                     if (_keylist == NULL) {
   549                         free_stringlist(recipient_keylist);
   550                         if (*keylist)
   551                             free_stringlist(*keylist);
   552                         *keylist = NULL;
   553                         result = PEP_OUT_OF_MEMORY;
   554                     }
   555                     // Get filename, if desired
   556                     if (filename_ptr) {
   557                         const char* fname = gpgme_decrypt_result->file_name;
   558                         if (fname) {
   559                             *filename_ptr = strdup(fname);
   560                             if (!(*filename_ptr))
   561                                 result = PEP_OUT_OF_MEMORY;
   562                         }
   563                     }                    
   564                 } /* Ok, so now we have any recipients it was encrypted for
   565                      in recipient_keylist */
   566             
   567                    
   568                 gpgme_verify_result_t gpgme_verify_result;
   569                 char *_buffer = NULL;
   570                 size_t reading;
   571                 size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
   572                 gpgme_signature_t gpgme_signature;
   573 
   574                 assert(length != -1);
   575                 gpg.gpgme_data_seek(plain, 0, SEEK_SET);
   576 
   577                 // TODO: make things less memory consuming
   578                 // the following algorithm allocates memory for the complete
   579                 // text
   580 
   581                 _buffer = malloc(length + 1);
   582                 assert(_buffer);
   583                 if (_buffer == NULL) {
   584                     gpg.gpgme_data_release(plain);
   585                     gpg.gpgme_data_release(cipher);
   586                     if (recipient_keylist)
   587                         free_stringlist(recipient_keylist);
   588                     return PEP_OUT_OF_MEMORY;
   589                 }
   590 
   591                 reading = gpg.gpgme_data_read(plain, _buffer, length);
   592                 assert(length == reading);
   593 
   594                 if (dsigtext) {  // Is this safe to do?
   595                     gpgme_data_t sigdata;
   596                     gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
   597                                                 dsigsize, 0);
   598                     gpg.gpgme_op_verify(session->ctx, sigdata, plain, NULL);
   599                     gpg.gpgme_data_release(sigdata);
   600                 }
   601 
   602                 gpgme_verify_result =
   603                     gpg.gpgme_op_verify_result(session->ctx);
   604                 assert(gpgme_verify_result);
   605                 gpgme_signature = gpgme_verify_result->signatures;
   606 
   607                 if (!gpgme_signature) {
   608                     // try cleartext sig verification
   609                     gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
   610                     gpgme_verify_result =
   611                         gpg.gpgme_op_verify_result(session->ctx);
   612                             assert(gpgme_verify_result);
   613                     gpgme_signature = gpgme_verify_result->signatures;
   614                 }
   615 
   616                 if (gpgme_signature) {
   617                     stringlist_t *k;
   618                     _keylist = new_stringlist(NULL);
   619                     assert(_keylist);
   620                     if (_keylist == NULL) {
   621                         gpg.gpgme_data_release(plain);
   622                         gpg.gpgme_data_release(cipher);
   623                         free(_buffer);
   624                         return PEP_OUT_OF_MEMORY;
   625                     }
   626                     k = _keylist;
   627 
   628                     result = PEP_DECRYPTED_AND_VERIFIED;
   629                     gpg.gpgme_check(NULL);
   630                     do { /* get all signers and put them at the front off
   631                             the keylist (likely only one) */
   632                         switch (_GPGERR(gpgme_signature->status)) {
   633                         case GPG_ERR_NO_ERROR:
   634                         {
   635                             // Some versions of gpg returns signer's
   636                             // signing subkey fingerprint instead of
   637                             // signer's primary key fingerprint.
   638                             // This is meant to get signer's primary
   639                             // key fingerprint, using subkey's.
   640 
   641                             gpgme_key_t key = NULL;
   642 
   643                             gpgme_error = gpg.gpgme_get_key(session->ctx,
   644                                 gpgme_signature->fpr, &key, 0);
   645                             gpgme_error = _GPGERR(gpgme_error);
   646                             assert(gpgme_error != GPG_ERR_ENOMEM);
   647                             if (gpgme_error == GPG_ERR_ENOMEM) {
   648                                 free_stringlist(_keylist);
   649                                 gpg.gpgme_data_release(plain);
   650                                 gpg.gpgme_data_release(cipher);
   651                                 free(_buffer);
   652                                 return PEP_OUT_OF_MEMORY;
   653                             }
   654                             // Primary key is given as the first subkey
   655                             if (gpgme_error == GPG_ERR_NO_ERROR &&
   656                                 key && key->subkeys && key->subkeys->fpr
   657                                 && key->subkeys->fpr[0])
   658                             {
   659                                 k = stringlist_add(k, key->subkeys->fpr);
   660 
   661                                 gpg.gpgme_key_unref(key);
   662 
   663                                 if (k == NULL) {
   664                                     free_stringlist(_keylist);
   665                                     if (recipient_keylist)
   666                                         free (recipient_keylist);
   667                                     gpg.gpgme_data_release(plain);
   668                                     gpg.gpgme_data_release(cipher);
   669                                     free(_buffer);
   670                                     return PEP_OUT_OF_MEMORY;
   671                                 }
   672                             }
   673                             else
   674                             {
   675                                 result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   676                                 break;
   677                             }
   678                             break;
   679                         }
   680                         case GPG_ERR_CERT_REVOKED:
   681                             result = PEP_VERIFY_SIGNER_KEY_REVOKED;
   682                             break;
   683                         case GPG_ERR_BAD_SIGNATURE:
   684                             result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   685                             //result = PEP_DECRYPT_BAD_SIGNATURE;
   686                             break;
   687                         case GPG_ERR_SIG_EXPIRED:
   688                         case GPG_ERR_KEY_EXPIRED:
   689                         case GPG_ERR_NO_PUBKEY:
   690                             k = stringlist_add(k, gpgme_signature->fpr);
   691                             if (k == NULL) {
   692                                 free_stringlist(_keylist);
   693                                 if (recipient_keylist)
   694                                     free_stringlist(recipient_keylist);
   695                                 gpg.gpgme_data_release(plain);
   696                                 gpg.gpgme_data_release(cipher);
   697                                 free(_buffer);
   698                                 return PEP_OUT_OF_MEMORY;
   699                             }
   700                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   701                                 result = PEP_DECRYPTED;
   702                             break;
   703                         case GPG_ERR_GENERAL:
   704                             break;
   705                         default:
   706                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   707                                 result = PEP_DECRYPTED;
   708                             break;
   709                         }
   710                     } while ((gpgme_signature = gpgme_signature->next));
   711                 }
   712                 else {
   713                     result = PEP_DECRYPTED;
   714                 }
   715 
   716                 if (result == PEP_DECRYPTED_AND_VERIFIED
   717                     || result == PEP_DECRYPTED) {
   718                     *ptext = _buffer;
   719                     *psize = reading;
   720                     (*ptext)[*psize] = 0; // safeguard for naive users
   721                     *keylist = _keylist;
   722                     if (recipient_keylist) {
   723                         if (!_keylist)
   724                             *keylist = new_stringlist(""); // no sig
   725                         if (!(*keylist)) {
   726                             free_stringlist(_keylist);
   727                             if (recipient_keylist)
   728                                 free_stringlist(recipient_keylist);
   729                             gpg.gpgme_data_release(plain);
   730                             gpg.gpgme_data_release(cipher);
   731                             free(_buffer);
   732                             return PEP_OUT_OF_MEMORY;
   733                         }
   734                         stringlist_append(*keylist, recipient_keylist);
   735                     }
   736                 }
   737                 else {
   738                     free_stringlist(_keylist);
   739                     if (recipient_keylist)
   740                         free_stringlist(recipient_keylist);
   741                     free(_buffer);
   742                 }
   743                 break;
   744             }
   745             case GPG_ERR_BAD_PASSPHRASE:
   746             case GPG_ERR_NO_DATA:
   747                 result = PEP_DECRYPT_NO_KEY;
   748                 break;
   749             case GPG_ERR_DECRYPT_FAILED:
   750             default:
   751             {
   752                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   753                 result = PEP_DECRYPT_NO_KEY;
   754 
   755                 if (gpgme_decrypt_result != NULL) {
   756                     if (gpgme_decrypt_result->unsupported_algorithm)
   757                         *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   758                     else
   759                         *keylist = new_stringlist("");
   760                     assert(*keylist);
   761                     if (*keylist == NULL) {
   762                         result = PEP_OUT_OF_MEMORY;
   763                         break;
   764                     }
   765                 }
   766             }
   767         }
   768         break;
   769 
   770     default:
   771         result = PEP_DECRYPT_WRONG_FORMAT;
   772     }
   773 
   774     gpg.gpgme_data_release(plain);
   775     gpg.gpgme_data_release(cipher);
   776     return result;
   777 }
   778 
   779 PEP_STATUS pgp_verify_text(
   780     PEP_SESSION session, const char *text, size_t size,
   781     const char *signature, size_t sig_size, stringlist_t **keylist
   782     )
   783 {
   784     PEP_STATUS result;
   785     gpgme_error_t gpgme_error;
   786     gpgme_data_t d_text, d_sig;
   787     stringlist_t *_keylist;
   788 
   789     assert(session);
   790     assert(text);
   791     assert(size);
   792     assert(signature);
   793     assert(sig_size);
   794     assert(keylist);
   795 
   796     *keylist = NULL;
   797 
   798     gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   799     gpgme_error = _GPGERR(gpgme_error);
   800     assert(gpgme_error == GPG_ERR_NO_ERROR);
   801     if (gpgme_error != GPG_ERR_NO_ERROR) {
   802         if (gpgme_error == GPG_ERR_ENOMEM)
   803             return PEP_OUT_OF_MEMORY;
   804         else
   805             return PEP_UNKNOWN_ERROR;
   806     }
   807 
   808     gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   809     gpgme_error = _GPGERR(gpgme_error);
   810     assert(gpgme_error == GPG_ERR_NO_ERROR);
   811     if (gpgme_error != GPG_ERR_NO_ERROR) {
   812         gpg.gpgme_data_release(d_text);
   813         if (gpgme_error == GPG_ERR_ENOMEM)
   814             return PEP_OUT_OF_MEMORY;
   815         else
   816             return PEP_UNKNOWN_ERROR;
   817     }
   818 
   819     gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
   820     gpgme_error = _GPGERR(gpgme_error);
   821     assert(gpgme_error != GPG_ERR_INV_VALUE);
   822 
   823     switch (gpgme_error) {
   824     case GPG_ERR_NO_ERROR:
   825     {
   826         gpgme_verify_result_t gpgme_verify_result;
   827         gpgme_signature_t gpgme_signature;
   828 
   829         gpgme_verify_result =
   830             gpg.gpgme_op_verify_result(session->ctx);
   831         assert(gpgme_verify_result);
   832         gpgme_signature = gpgme_verify_result->signatures;
   833 
   834         if (gpgme_signature) {
   835             stringlist_t *k;
   836             _keylist = new_stringlist(NULL);
   837             assert(_keylist);
   838             if (_keylist == NULL) {
   839                 gpg.gpgme_data_release(d_text);
   840                 gpg.gpgme_data_release(d_sig);
   841                 return PEP_OUT_OF_MEMORY;
   842             }
   843             k = _keylist;
   844 
   845             result = PEP_VERIFIED;
   846             do {
   847                 gpgme_key_t key;
   848                 memset(&key,0,sizeof(key));
   849 
   850                 // GPGME may give subkey's fpr instead of primary key's fpr.
   851                 // Therefore we ask for the primary fingerprint instead
   852                 // we assume that gpgme_get_key can find key by subkey's fpr
   853                 gpgme_error = gpg.gpgme_get_key(session->ctx,
   854                     gpgme_signature->fpr, &key, 0);
   855                 gpgme_error = _GPGERR(gpgme_error);
   856                 assert(gpgme_error != GPG_ERR_ENOMEM);
   857                 if (gpgme_error == GPG_ERR_ENOMEM) {
   858                     free_stringlist(_keylist);
   859                     gpg.gpgme_data_release(d_text);
   860                     gpg.gpgme_data_release(d_sig);
   861                     return PEP_OUT_OF_MEMORY;
   862                 }
   863                 // Primary key is given as the first subkey
   864                 if (gpgme_error == GPG_ERR_NO_ERROR &&
   865                     key && key->subkeys && key->subkeys->fpr
   866                     && key->subkeys->fpr[0])
   867                 {
   868                     k = stringlist_add(k, key->subkeys->fpr);
   869 
   870                     gpg.gpgme_key_unref(key);
   871 
   872                     if (k == NULL) {
   873                         free_stringlist(_keylist);
   874                         gpg.gpgme_data_release(d_text);
   875                         gpg.gpgme_data_release(d_sig);
   876                         return PEP_OUT_OF_MEMORY;
   877                     }
   878                 }
   879                 else {
   880                     result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   881                     break;
   882                 }
   883 
   884                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   885                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   886                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   887                         if (result == PEP_VERIFIED
   888                             || result == PEP_VERIFIED_AND_TRUSTED)
   889                             result = PEP_UNENCRYPTED;
   890                     }
   891                     else {
   892                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   893                         break;
   894                     }
   895                 }
   896                 else {
   897                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   898                         if (result == PEP_VERIFIED)
   899                             result = PEP_VERIFIED_AND_TRUSTED;
   900                     }
   901                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   902                         // good
   903                     }
   904                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   905                         result = PEP_VERIFY_NO_KEY;
   906                     }
   907                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   908                         if (result == PEP_VERIFIED
   909                             || result == PEP_VERIFIED_AND_TRUSTED)
   910                             result = PEP_UNENCRYPTED;
   911                     }
   912                     else {
   913                         // do nothing
   914                     }
   915                 }
   916             } while ((gpgme_signature = gpgme_signature->next));
   917             *keylist = _keylist;
   918         }
   919         else {
   920             result = PEP_UNENCRYPTED;
   921         }
   922         break;
   923     }
   924         break;
   925     case GPG_ERR_NO_DATA:
   926         result = PEP_DECRYPT_WRONG_FORMAT;
   927         break;
   928     case GPG_ERR_INV_VALUE:
   929     default:
   930         result = PEP_UNKNOWN_ERROR;
   931         break;
   932     }
   933 
   934     gpg.gpgme_data_release(d_text);
   935     gpg.gpgme_data_release(d_sig);
   936 
   937     return result;
   938 }
   939 
   940 PEP_STATUS pgp_sign_only(    
   941     PEP_SESSION session, const char* fpr, const char *ptext,
   942     size_t psize, char **stext, size_t *ssize
   943 )
   944 {
   945     assert(session);
   946     assert(fpr && fpr[0]);
   947     assert(ptext);
   948     assert(psize);
   949     assert(stext);
   950     assert(ssize);
   951 
   952     PEP_STATUS result;
   953     gpgme_error_t gpgme_error;
   954     gpgme_data_t plain, signed_text;
   955     gpgme_key_t* signer_key_ptr;
   956 
   957     gpgme_sig_mode_t sign_mode = GPGME_SIG_MODE_DETACH;
   958        
   959     *stext = NULL;
   960     *ssize = 0;
   961 
   962     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
   963     gpgme_error = _GPGERR(gpgme_error);
   964     assert(gpgme_error == GPG_ERR_NO_ERROR);
   965     if (gpgme_error != GPG_ERR_NO_ERROR) {
   966         if (gpgme_error == GPG_ERR_ENOMEM)
   967             return PEP_OUT_OF_MEMORY;
   968         else
   969             return PEP_UNKNOWN_ERROR;
   970     }
   971 
   972     gpgme_error = gpg.gpgme_data_new(&signed_text);
   973     gpgme_error = _GPGERR(gpgme_error);
   974     assert(gpgme_error == GPG_ERR_NO_ERROR);
   975     if (gpgme_error != GPG_ERR_NO_ERROR) {
   976         gpg.gpgme_data_release(plain);
   977         if (gpgme_error == GPG_ERR_ENOMEM)
   978             return PEP_OUT_OF_MEMORY;
   979         else
   980             return PEP_UNKNOWN_ERROR;
   981     }
   982 
   983     signer_key_ptr = calloc(1, sizeof(gpgme_key_t));   
   984     assert(signer_key_ptr);
   985     if (signer_key_ptr == NULL) {
   986         gpg.gpgme_data_release(plain);
   987         gpg.gpgme_data_release(signed_text);
   988         return PEP_OUT_OF_MEMORY;
   989     }
   990 
   991     gpg.gpgme_signers_clear(session->ctx);
   992 
   993     // Get signing key
   994     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr,
   995                                     signer_key_ptr, 0);
   996     gpgme_error = _GPGERR(gpgme_error);
   997     assert(gpgme_error != GPG_ERR_ENOMEM);
   998     gpgme_error_t _gpgme_error;
   999     
  1000     switch (gpgme_error) {
  1001     case GPG_ERR_ENOMEM:
  1002         gpg.gpgme_key_unref(*signer_key_ptr);
  1003         free(signer_key_ptr);
  1004         gpg.gpgme_data_release(plain);
  1005         gpg.gpgme_data_release(signed_text);
  1006         return PEP_OUT_OF_MEMORY;
  1007     case GPG_ERR_NO_ERROR:
  1008         _gpgme_error = gpg.gpgme_signers_add(session->ctx, *signer_key_ptr);
  1009         _gpgme_error = _GPGERR(_gpgme_error);
  1010         assert(_gpgme_error == GPG_ERR_NO_ERROR);
  1011         break;
  1012     case GPG_ERR_EOF:
  1013         gpg.gpgme_key_unref(*signer_key_ptr);
  1014         free(signer_key_ptr);
  1015         gpg.gpgme_data_release(plain);
  1016         gpg.gpgme_data_release(signed_text);
  1017         return PEP_KEY_NOT_FOUND;
  1018     case GPG_ERR_AMBIGUOUS_NAME:
  1019         gpg.gpgme_key_unref(*signer_key_ptr);
  1020         free(signer_key_ptr);
  1021         gpg.gpgme_data_release(plain);
  1022         gpg.gpgme_data_release(signed_text);
  1023         return PEP_KEY_HAS_AMBIG_NAME;
  1024     default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
  1025         // FPR is not a fingerprint or key ID
  1026         gpg.gpgme_key_unref(*signer_key_ptr);
  1027         free(signer_key_ptr);
  1028         gpg.gpgme_data_release(plain);
  1029         gpg.gpgme_data_release(signed_text);
  1030         return PEP_GET_KEY_FAILED;
  1031     }
  1032  
  1033     gpgme_error = gpg.gpgme_op_sign(session->ctx, plain, signed_text, sign_mode);
  1034 
  1035     gpgme_error = _GPGERR(gpgme_error);
  1036     switch (gpgme_error) {
  1037     case GPG_ERR_NO_ERROR:
  1038     {
  1039         char *_buffer = NULL;
  1040         size_t reading;
  1041         size_t length = gpg.gpgme_data_seek(signed_text, 0, SEEK_END);
  1042         assert(length != -1);
  1043         gpg.gpgme_data_seek(signed_text, 0, SEEK_SET);
  1044 
  1045         // TODO: make things less memory consuming
  1046         // the following algorithm allocates a buffer for the complete text
  1047 
  1048         _buffer = malloc(length + 1);
  1049         assert(_buffer);
  1050         if (_buffer == NULL) {
  1051             gpg.gpgme_key_unref(*signer_key_ptr);
  1052             free(signer_key_ptr);
  1053             gpg.gpgme_data_release(plain);
  1054             gpg.gpgme_data_release(signed_text);
  1055             return PEP_OUT_OF_MEMORY;
  1056         }
  1057 
  1058         reading = gpg.gpgme_data_read(signed_text, _buffer, length);
  1059         assert(length == reading);
  1060 
  1061         *stext = _buffer;
  1062         *ssize = reading;
  1063         (*stext)[*ssize] = 0; // safeguard for naive users
  1064         result = PEP_STATUS_OK;
  1065         break;
  1066     }
  1067     default:
  1068         result = PEP_UNKNOWN_ERROR;
  1069     }
  1070 
  1071     gpg.gpgme_key_unref(*signer_key_ptr);
  1072     free(signer_key_ptr);
  1073     gpg.gpgme_data_release(plain);
  1074     gpg.gpgme_data_release(signed_text);
  1075     return result;   
  1076 }
  1077 
  1078 static PEP_STATUS pgp_encrypt_sign_optional(    
  1079     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1080     size_t psize, char **ctext, size_t *csize, bool sign
  1081 )
  1082 {
  1083     PEP_STATUS result;
  1084     gpgme_error_t gpgme_error;
  1085     gpgme_data_t plain, cipher;
  1086     gpgme_key_t *rcpt;
  1087     gpgme_encrypt_flags_t flags;
  1088     const stringlist_t *_keylist;
  1089     int i, j;
  1090 
  1091     assert(session);
  1092     assert(keylist);
  1093     assert(ptext);
  1094     assert(psize);
  1095     assert(ctext);
  1096     assert(csize);
  1097 
  1098     *ctext = NULL;
  1099     *csize = 0;
  1100 
  1101     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
  1102     gpgme_error = _GPGERR(gpgme_error);
  1103     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1104     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1105         if (gpgme_error == GPG_ERR_ENOMEM)
  1106             return PEP_OUT_OF_MEMORY;
  1107         else
  1108             return PEP_UNKNOWN_ERROR;
  1109     }
  1110 
  1111     gpgme_error = gpg.gpgme_data_new(&cipher);
  1112     gpgme_error = _GPGERR(gpgme_error);
  1113     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1114     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1115         gpg.gpgme_data_release(plain);
  1116         if (gpgme_error == GPG_ERR_ENOMEM)
  1117             return PEP_OUT_OF_MEMORY;
  1118         else
  1119             return PEP_UNKNOWN_ERROR;
  1120     }
  1121 
  1122     rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
  1123     assert(rcpt);
  1124     if (rcpt == NULL) {
  1125         gpg.gpgme_data_release(plain);
  1126         gpg.gpgme_data_release(cipher);
  1127         return PEP_OUT_OF_MEMORY;
  1128     }
  1129 
  1130     gpg.gpgme_signers_clear(session->ctx);
  1131 
  1132     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
  1133         assert(_keylist->value);
  1134         gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
  1135             &rcpt[i], 0);
  1136         gpgme_error = _GPGERR(gpgme_error);
  1137         assert(gpgme_error != GPG_ERR_ENOMEM);
  1138 
  1139         switch (gpgme_error) {
  1140         case GPG_ERR_ENOMEM:
  1141             for (j = 0; j<i; j++)
  1142                 gpg.gpgme_key_unref(rcpt[j]);
  1143             free(rcpt);
  1144             gpg.gpgme_data_release(plain);
  1145             gpg.gpgme_data_release(cipher);
  1146             return PEP_OUT_OF_MEMORY;
  1147         case GPG_ERR_NO_ERROR:
  1148             if (i == 0 && sign) {
  1149                 gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
  1150                 _gpgme_error = _GPGERR(_gpgme_error);
  1151                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
  1152             }
  1153             break;
  1154         case GPG_ERR_EOF:
  1155             for (j = 0; j<i; j++)
  1156                 gpg.gpgme_key_unref(rcpt[j]);
  1157             free(rcpt);
  1158             gpg.gpgme_data_release(plain);
  1159             gpg.gpgme_data_release(cipher);
  1160             return PEP_KEY_NOT_FOUND;
  1161         case GPG_ERR_AMBIGUOUS_NAME:
  1162             for (j = 0; j<i; j++)
  1163                 gpg.gpgme_key_unref(rcpt[j]);
  1164             free(rcpt);
  1165             gpg.gpgme_data_release(plain);
  1166             gpg.gpgme_data_release(cipher);
  1167             return PEP_KEY_HAS_AMBIG_NAME;
  1168         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
  1169             // FPR is not a fingerprint or key ID
  1170             for (j = 0; j<i; j++)
  1171                 gpg.gpgme_key_unref(rcpt[j]);
  1172             free(rcpt);
  1173             gpg.gpgme_data_release(plain);
  1174             gpg.gpgme_data_release(cipher);
  1175             return PEP_GET_KEY_FAILED;
  1176         }
  1177     }
  1178 
  1179     // TODO: remove that and replace with proper key management
  1180     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
  1181     
  1182     if (sign) {
  1183         gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
  1184             plain, cipher);
  1185     }
  1186     else {
  1187         gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
  1188             plain, cipher);
  1189     }
  1190     
  1191     gpgme_error = _GPGERR(gpgme_error);
  1192     switch (gpgme_error) {
  1193     case GPG_ERR_NO_ERROR:
  1194     {
  1195         char *_buffer = NULL;
  1196         size_t reading;
  1197         size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
  1198         assert(length != -1);
  1199         gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
  1200 
  1201         // TODO: make things less memory consuming
  1202         // the following algorithm allocates a buffer for the complete text
  1203 
  1204         _buffer = malloc(length + 1);
  1205         assert(_buffer);
  1206         if (_buffer == NULL) {
  1207             for (j = 0; j<stringlist_length(keylist); j++)
  1208                 gpg.gpgme_key_unref(rcpt[j]);
  1209             free(rcpt);
  1210             gpg.gpgme_data_release(plain);
  1211             gpg.gpgme_data_release(cipher);
  1212             return PEP_OUT_OF_MEMORY;
  1213         }
  1214 
  1215         reading = gpg.gpgme_data_read(cipher, _buffer, length);
  1216         assert(length == reading);
  1217 
  1218         *ctext = _buffer;
  1219         *csize = reading;
  1220         (*ctext)[*csize] = 0; // safeguard for naive users
  1221         result = PEP_STATUS_OK;
  1222         break;
  1223     }
  1224     default:
  1225         result = PEP_UNKNOWN_ERROR;
  1226     }
  1227 
  1228     for (j = 0; j<stringlist_length(keylist); j++)
  1229         gpg.gpgme_key_unref(rcpt[j]);
  1230     free(rcpt);
  1231     gpg.gpgme_data_release(plain);
  1232     gpg.gpgme_data_release(cipher);
  1233     return result;
  1234 }
  1235 
  1236 PEP_STATUS pgp_encrypt_only(
  1237     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1238     size_t psize, char **ctext, size_t *csize
  1239     )
  1240 {
  1241     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1242         psize, ctext, csize, false);
  1243 }
  1244 
  1245 PEP_STATUS pgp_encrypt_and_sign(
  1246     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1247     size_t psize, char **ctext, size_t *csize
  1248     )
  1249 {
  1250     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1251         psize, ctext, csize, true);
  1252 }
  1253 
  1254 
  1255 static PEP_STATUS find_single_key(
  1256         PEP_SESSION session,
  1257         const char *fpr,
  1258         gpgme_key_t *key
  1259     )
  1260 {
  1261     gpgme_error_t gpgme_error;
  1262 
  1263     *key = NULL;
  1264 
  1265 //    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1266 
  1267     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, key, 0);
  1268 
  1269     gpgme_error = _GPGERR(gpgme_error);
  1270     switch (gpgme_error) {
  1271     case GPG_ERR_NO_ERROR:
  1272         break;
  1273     case GPG_ERR_INV_VALUE:
  1274         assert(0);
  1275         return PEP_UNKNOWN_ERROR;
  1276     default:
  1277         return PEP_GET_KEY_FAILED;
  1278     };
  1279 
  1280 //    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1281 //    gpgme_error = _GPGERR(gpgme_error);
  1282 //    assert(gpgme_error != GPG_ERR_INV_VALUE);
  1283 
  1284 //    gpg.gpgme_op_keylist_end(session->ctx);
  1285 
  1286     return PEP_STATUS_OK;
  1287 }
  1288 
  1289 
  1290 static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
  1291     PEP_STATUS status = PEP_VERSION_MISMATCH;
  1292 
  1293     if (identity && identity->address) {
  1294 #ifdef GPGME_VERSION_NUMBER 
  1295 #if (GPGME_VERSION_NUMBER >= 0x010700)
  1296         gpgme_error_t gpgme_error;
  1297         int userid_size = strlen(identity->address) + 1;
  1298         char* userid = (char*)(calloc(1, userid_size));
  1299         if (!userid)
  1300             return PEP_OUT_OF_MEMORY;
  1301         strlcpy(userid, identity->address, userid_size);
  1302         gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
  1303                                              0, 31536000, NULL, 
  1304                                              GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE);
  1305         gpgme_error = _GPGERR(gpgme_error);
  1306 
  1307         free(userid);
  1308 
  1309         if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
  1310             switch (gpgme_error) {
  1311                 case GPG_ERR_NO_ERROR:
  1312                     break;
  1313                 case GPG_ERR_INV_VALUE:
  1314                     return PEP_ILLEGAL_VALUE;
  1315                 default:
  1316                     return PEP_CANNOT_CREATE_KEY;
  1317             }
  1318 
  1319             /* This is the same regardless of whether we got it from genkey or createkey */
  1320             gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1321             assert(gpgme_genkey_result);
  1322             assert(gpgme_genkey_result->fpr);
  1323 
  1324             char* fpr = strdup(gpgme_genkey_result->fpr);
  1325             gpgme_key_t key;
  1326             PEP_STATUS key_status = find_single_key(session, fpr, &key);
  1327             if (!key || key_status != PEP_STATUS_OK)
  1328                 return PEP_CANNOT_CREATE_KEY;
  1329             
  1330             gpgme_error = gpg.gpgme_op_createsubkey(session->ctx, key, 
  1331                                                     "RSA", 0, 
  1332                                                     31536000, GPGME_CREATE_NOPASSWD 
  1333                                                     | GPGME_CREATE_ENCR);
  1334 
  1335             switch (gpgme_error) {
  1336                 case GPG_ERR_NO_ERROR:
  1337                     break;
  1338                 case GPG_ERR_INV_VALUE:
  1339                     return PEP_ILLEGAL_VALUE;
  1340                 case GPG_ERR_GENERAL:
  1341                     return PEP_CANNOT_CREATE_KEY;
  1342                 default:
  1343                     assert(0);
  1344                     return PEP_UNKNOWN_ERROR;
  1345             }
  1346             
  1347             free(identity->fpr);
  1348             identity->fpr = fpr;
  1349             if (identity->fpr == NULL)
  1350                 return PEP_OUT_OF_MEMORY;
  1351 
  1352 //            gpg.gpgme_key_unref(key);
  1353             
  1354             status = pgp_replace_only_uid(session, fpr,
  1355                         identity->username, identity->address);
  1356         }
  1357 #endif
  1358 #endif
  1359     }
  1360     
  1361     return status;
  1362 }
  1363 
  1364 PEP_STATUS pgp_generate_keypair(
  1365     PEP_SESSION session, pEp_identity *identity
  1366     )
  1367 {
  1368     assert(session);
  1369     assert(identity);
  1370     assert(identity->address);
  1371     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1372     assert(identity->username);
  1373 
  1374     PEP_STATUS status = _pgp_createkey(session, identity);
  1375     
  1376     if (status != PEP_VERSION_MISMATCH)
  1377         return status;
  1378         
  1379     gpgme_error_t gpgme_error;
  1380     char *parms;
  1381     const char *template =
  1382         "<GnupgKeyParms format=\"internal\">\n"
  1383         "Key-Type: RSA\n"
  1384         "Key-Length: 4096\n"
  1385         "Subkey-Type: RSA\n"
  1386         "Subkey-Length: 4096\n"
  1387         "Name-Real: %s\n"
  1388         "Name-Email: %s\n"
  1389         /* "Passphrase: %s\n" */
  1390         "Expire-Date: 1y\n"
  1391         "</GnupgKeyParms>\n";
  1392     int result;
  1393 
  1394     parms = calloc(1, PARMS_MAX);
  1395     assert(parms);
  1396     if (parms == NULL)
  1397         return PEP_OUT_OF_MEMORY;
  1398 
  1399     result = snprintf(parms, PARMS_MAX, template, identity->username,
  1400         identity->address); // , session->passphrase);
  1401     assert(result < PARMS_MAX);
  1402     if (result >= PARMS_MAX) {
  1403         free(parms);
  1404         return PEP_BUFFER_TOO_SMALL;
  1405     }
  1406 
  1407     gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
  1408     gpgme_error = _GPGERR(gpgme_error);
  1409     free(parms);
  1410 
  1411     switch (gpgme_error) {
  1412     case GPG_ERR_NO_ERROR:
  1413         break;
  1414     case GPG_ERR_INV_VALUE:
  1415         return PEP_ILLEGAL_VALUE;
  1416     case GPG_ERR_GENERAL:
  1417         return PEP_CANNOT_CREATE_KEY;
  1418     default:
  1419         assert(0);
  1420         return PEP_UNKNOWN_ERROR;
  1421     }
  1422 
  1423     gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1424     assert(gpgme_genkey_result);
  1425     assert(gpgme_genkey_result->fpr);
  1426 
  1427     free(identity->fpr);
  1428     identity->fpr = strdup(gpgme_genkey_result->fpr);
  1429     if (identity->fpr == NULL)
  1430         return PEP_OUT_OF_MEMORY;
  1431 
  1432     return PEP_STATUS_OK;
  1433 }
  1434 
  1435 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
  1436 {
  1437     gpgme_error_t gpgme_error;
  1438     gpgme_key_t key;
  1439 
  1440     assert(session);
  1441     assert(fpr);
  1442 
  1443     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1444     gpgme_error = _GPGERR(gpgme_error);
  1445     assert(gpgme_error != GPG_ERR_ENOMEM);
  1446     switch (gpgme_error) {
  1447     case GPG_ERR_NO_ERROR:
  1448         break;
  1449     case GPG_ERR_EOF:
  1450         return PEP_KEY_NOT_FOUND;
  1451     case GPG_ERR_INV_VALUE:
  1452         return PEP_ILLEGAL_VALUE;
  1453     case GPG_ERR_AMBIGUOUS_NAME:
  1454         return PEP_KEY_HAS_AMBIG_NAME;
  1455     case GPG_ERR_ENOMEM:
  1456         return PEP_OUT_OF_MEMORY;
  1457     default:
  1458         assert(0);
  1459         return PEP_UNKNOWN_ERROR;
  1460     }
  1461 
  1462     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1463     gpgme_error = _GPGERR(gpgme_error);
  1464     gpg.gpgme_key_unref(key);
  1465     switch (gpgme_error) {
  1466     case GPG_ERR_NO_ERROR:
  1467         break;
  1468     case GPG_ERR_INV_VALUE:
  1469         assert(0);
  1470         return PEP_UNKNOWN_ERROR;
  1471     case GPG_ERR_NO_PUBKEY:
  1472         assert(0);
  1473         return PEP_KEY_NOT_FOUND;
  1474     case GPG_ERR_AMBIGUOUS_NAME:
  1475         assert(0);
  1476         return PEP_KEY_HAS_AMBIG_NAME;
  1477     default:
  1478         assert(0);
  1479         return PEP_UNKNOWN_ERROR;
  1480     }
  1481 
  1482     return PEP_STATUS_OK;
  1483 }
  1484 
  1485 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1486                               size_t size, identity_list **private_idents)
  1487 {
  1488     gpgme_error_t gpgme_error;
  1489     gpgme_data_t dh;
  1490 
  1491     assert(session);
  1492     assert(key_data);
  1493 
  1494     if(private_idents)
  1495         *private_idents = NULL;
  1496 
  1497     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1498     gpgme_error = _GPGERR(gpgme_error);
  1499     assert(gpgme_error != GPG_ERR_ENOMEM);
  1500     switch (gpgme_error) {
  1501     case GPG_ERR_NO_ERROR:
  1502         break;
  1503     case GPG_ERR_ENOMEM:
  1504         return PEP_OUT_OF_MEMORY;
  1505     case GPG_ERR_INV_VALUE:
  1506         assert(0);
  1507         return PEP_UNKNOWN_ERROR;
  1508     default:
  1509         assert(0);
  1510         return PEP_UNKNOWN_ERROR;
  1511     }
  1512 
  1513     gpgme_import_result_t gpgme_import_result;
  1514 
  1515     bool key_imported = false;
  1516     
  1517     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1518     gpgme_error = _GPGERR(gpgme_error);
  1519     switch (gpgme_error) {
  1520     case GPG_ERR_NO_ERROR:
  1521     
  1522         gpgme_import_result =
  1523             gpg.gpgme_op_import_result(session->ctx);
  1524         assert(gpgme_import_result);
  1525         if (!gpgme_import_result) {
  1526             gpg.gpgme_data_release(dh);
  1527             return PEP_UNKNOWN_ERROR;
  1528         }
  1529         // considered seems to only be true if it was 
  1530         // actually a key
  1531         if (gpgme_import_result->considered > 0)
  1532             // gpgme_import_result->imported > 0 ||
  1533             // gpgme_import_result->secret_imported > 0 ||
  1534             // gpgme_import_result->unchanged > 0 ||
  1535             // gpgme_import_result->secret_unchanged > 0)
  1536             key_imported = true;
  1537             
  1538         if(private_idents)
  1539         {
  1540             gpgme_import_status_t import;
  1541             for (import = gpgme_import_result->imports;
  1542                  import;
  1543                  import = import->next)
  1544              {
  1545                 if (import &&
  1546                     import->result == GPG_ERR_NO_ERROR &&
  1547                     import->status & GPGME_IMPORT_SECRET )
  1548                 {
  1549                     gpgme_key_t key = NULL;
  1550 
  1551                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1552                         import->fpr, &key, 0);
  1553                     gpgme_error = _GPGERR(gpgme_error);
  1554                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1555                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1556                         gpg.gpgme_data_release(dh);
  1557                         return PEP_OUT_OF_MEMORY;
  1558                     }
  1559 
  1560                     if (gpgme_error == GPG_ERR_NO_ERROR &&
  1561                         key && key->uids &&
  1562                         key->uids->email && key->uids->name)
  1563                     {
  1564                         pEp_identity *ident = new_identity(
  1565                              key->uids->email, import->fpr, NULL, key->uids->name);
  1566 
  1567                         gpg.gpgme_key_unref(key);
  1568 
  1569                         if (ident == NULL) {
  1570                             gpg.gpgme_data_release(dh);
  1571                             return PEP_OUT_OF_MEMORY;
  1572                         }
  1573 
  1574                         *private_idents = identity_list_add(*private_idents, ident);
  1575 
  1576                         if (*private_idents == NULL) {
  1577                             gpg.gpgme_data_release(dh);
  1578                             return PEP_OUT_OF_MEMORY;
  1579                         }
  1580                     }
  1581                     else
  1582                     {
  1583                         gpg.gpgme_key_unref(key);
  1584                         gpg.gpgme_data_release(dh);
  1585                         return PEP_UNKNOWN_ERROR;
  1586                     }
  1587                 }
  1588             }
  1589         }
  1590         break;
  1591     case GPG_ERR_INV_VALUE:
  1592         assert(0);
  1593         gpg.gpgme_data_release(dh);
  1594         return PEP_UNKNOWN_ERROR;
  1595     case GPG_ERR_NO_DATA:
  1596         gpg.gpgme_data_release(dh);
  1597         return PEP_ILLEGAL_VALUE;
  1598     default:
  1599         assert(0);
  1600         gpg.gpgme_data_release(dh);
  1601         return PEP_UNKNOWN_ERROR;
  1602     }
  1603 
  1604     gpg.gpgme_data_release(dh);
  1605     
  1606     if (key_imported)
  1607         return PEP_KEY_IMPORTED;
  1608         
  1609     return PEP_NO_KEY_IMPORTED;
  1610 }
  1611 
  1612 PEP_STATUS pgp_export_keydata(
  1613         PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
  1614         bool secret
  1615     )
  1616 {
  1617     gpgme_error_t gpgme_error;
  1618     gpgme_data_t dh;
  1619     size_t _size;
  1620     char *buffer = NULL;
  1621     int reading;
  1622 
  1623     assert(session);
  1624     assert(fpr);
  1625     assert(key_data);
  1626     assert(size);
  1627 
  1628     gpgme_error = gpg.gpgme_data_new(&dh);
  1629     gpgme_error = _GPGERR(gpgme_error);
  1630     assert(gpgme_error != GPG_ERR_ENOMEM);
  1631     switch (gpgme_error) {
  1632     case GPG_ERR_NO_ERROR:
  1633         break;
  1634     case GPG_ERR_ENOMEM:
  1635         return PEP_OUT_OF_MEMORY;
  1636     case GPG_ERR_INV_VALUE:
  1637         assert(0);
  1638         return PEP_UNKNOWN_ERROR;
  1639     default:
  1640         assert(0);
  1641         return PEP_UNKNOWN_ERROR;
  1642     }
  1643 
  1644     if (secret)
  1645         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1646             GPGME_EXPORT_MODE_SECRET, dh);
  1647     else
  1648         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1649             GPGME_EXPORT_MODE_MINIMAL, dh);
  1650     gpgme_error = _GPGERR(gpgme_error);
  1651     switch (gpgme_error) {
  1652     case GPG_ERR_NO_ERROR:
  1653         break;
  1654     case GPG_ERR_EOF:
  1655         gpg.gpgme_data_release(dh);
  1656         return PEP_KEY_NOT_FOUND;
  1657     case GPG_ERR_INV_VALUE:
  1658         assert(0);
  1659         gpg.gpgme_data_release(dh);
  1660         return PEP_UNKNOWN_ERROR;
  1661     default:
  1662         assert(0);
  1663         gpg.gpgme_data_release(dh);
  1664         return PEP_UNKNOWN_ERROR;
  1665     };
  1666 
  1667     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1668     assert(_size != -1);
  1669     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1670 
  1671     // Unfortunately, gpgme doesn't give us an error
  1672     // when no key is found, so we end up with an 
  1673     // empty string. So we need to do this:
  1674     if (_size == 0) {
  1675         *key_data = NULL;
  1676         *size = 0;
  1677         gpg.gpgme_data_release(dh);
  1678         return PEP_KEY_NOT_FOUND;
  1679     }
  1680         
  1681     buffer = malloc(_size + 1);
  1682     assert(buffer);
  1683     if (buffer == NULL) {
  1684         gpg.gpgme_data_release(dh);
  1685         return PEP_OUT_OF_MEMORY;
  1686     }
  1687 
  1688     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1689     assert(_size == reading);
  1690     if(_size != reading)
  1691         return PEP_CANNOT_EXPORT_KEY;
  1692 
  1693     // safeguard for the naive user
  1694     buffer[_size] = 0;
  1695 
  1696     *key_data = buffer;
  1697     *size = _size;
  1698 
  1699     gpg.gpgme_data_release(dh);
  1700     return PEP_STATUS_OK;
  1701 }
  1702 
  1703 PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
  1704                             stringpair_list_t** keyinfo_list)
  1705 {
  1706     gpgme_error_t gpgme_error;
  1707     assert(session);
  1708     assert(keyinfo_list);
  1709 
  1710     if (!session || !keyinfo_list)
  1711         return PEP_ILLEGAL_VALUE;
  1712 
  1713     *keyinfo_list = NULL;
  1714 
  1715     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1716     gpgme_error = _GPGERR(gpgme_error);
  1717 
  1718     switch(gpgme_error) {
  1719         case GPG_ERR_NO_ERROR:
  1720             break;
  1721         case GPG_ERR_INV_VALUE:
  1722             assert(0);
  1723             return PEP_UNKNOWN_ERROR;
  1724         default:
  1725             gpg.gpgme_op_keylist_end(session->ctx);
  1726             return PEP_GET_KEY_FAILED;
  1727     };
  1728 
  1729     gpgme_key_t key;
  1730     stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
  1731     stringpair_list_t* list_curr = _keyinfo_list;
  1732     stringpair_t* pair = NULL;
  1733 
  1734     do {
  1735         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1736         gpgme_error = _GPGERR(gpgme_error);
  1737 
  1738         switch(gpgme_error) {
  1739             case GPG_ERR_EOF:
  1740                 break;
  1741             case GPG_ERR_NO_ERROR:
  1742                 assert(key);
  1743                 assert(key->subkeys);
  1744                 if (!key || !key->subkeys)
  1745                     return PEP_GET_KEY_FAILED;
  1746 
  1747                 // first subkey is primary key
  1748                 char* fpr = key->subkeys->fpr;
  1749                 char* uid = key->uids->uid;
  1750 
  1751                 assert(fpr);
  1752                 assert(uid);
  1753                 if (!fpr)
  1754                     return PEP_GET_KEY_FAILED;
  1755 
  1756                 if (key->subkeys->revoked)
  1757                     continue;
  1758 
  1759                 pair = new_stringpair(fpr, uid);
  1760 
  1761                 assert(pair);
  1762 
  1763                 if (pair) {
  1764                     list_curr = stringpair_list_add(list_curr, pair);
  1765                     pair = NULL;
  1766 
  1767                     assert(list_curr);
  1768                     if (list_curr != NULL)
  1769                         break;
  1770                     else
  1771                         free_stringpair(pair);
  1772                 }
  1773                 // else fallthrough (list_curr or pair wasn't allocateable)
  1774             case GPG_ERR_ENOMEM:
  1775                 free_stringpair_list(_keyinfo_list);
  1776                 gpg.gpgme_op_keylist_end(session->ctx);
  1777                 return PEP_OUT_OF_MEMORY;
  1778             default:
  1779                 gpg.gpgme_op_keylist_end(session->ctx);
  1780                 return PEP_UNKNOWN_ERROR;
  1781         }
  1782     } while (gpgme_error != GPG_ERR_EOF);
  1783 
  1784     if (_keyinfo_list->value == NULL) {
  1785         free_stringpair_list(_keyinfo_list);
  1786         _keyinfo_list = NULL;
  1787     }
  1788 
  1789     *keyinfo_list = _keyinfo_list;
  1790 
  1791     return PEP_STATUS_OK;
  1792 }
  1793 
  1794 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1795     gpgme_keylist_mode_t add_mode)
  1796 {
  1797     gpgme_error_t gpgme_error;
  1798     gpgme_keylist_mode_t mode;
  1799 
  1800     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1801 
  1802     mode &= ~remove_mode;
  1803     mode |= add_mode;
  1804 
  1805     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1806     gpgme_error = _GPGERR(gpgme_error);
  1807     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1808 }
  1809 
  1810 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1811 {
  1812     gpgme_error_t gpgme_error;
  1813     gpgme_key_t key;
  1814 
  1815     assert(session);
  1816     assert(pattern);
  1817 
  1818     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1819 
  1820     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1821     gpgme_error = _GPGERR(gpgme_error);
  1822     switch (gpgme_error) {
  1823     case GPG_ERR_NO_ERROR:
  1824         break;
  1825     case GPG_ERR_INV_VALUE:
  1826         assert(0);
  1827         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1828         return PEP_UNKNOWN_ERROR;
  1829     default:
  1830         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1831         return PEP_GET_KEY_FAILED;
  1832     };
  1833 
  1834     gpgme_ctx_t import_ctx;
  1835     gpgme_error = gpg.gpgme_new(&import_ctx);
  1836     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1837 
  1838     do {
  1839         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1840         gpgme_error = _GPGERR(gpgme_error);
  1841         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1842         switch (gpgme_error) {
  1843         case GPG_ERR_EOF:
  1844             break;
  1845         case GPG_ERR_NO_ERROR:
  1846         {
  1847             gpgme_error_t gpgme_error;
  1848             gpgme_key_t keys[2];
  1849 
  1850             keys[0] = key;
  1851             keys[1] = NULL;
  1852 
  1853             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1854             gpgme_error = _GPGERR(gpgme_error);
  1855             gpg.gpgme_key_unref(key);
  1856             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1857             assert(gpgme_error != GPG_ERR_CONFLICT);
  1858         }
  1859             break;
  1860         case GPG_ERR_ENOMEM:
  1861             gpg.gpgme_op_keylist_end(session->ctx);
  1862             gpg.gpgme_release(import_ctx);
  1863             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1864             return PEP_OUT_OF_MEMORY;
  1865         default:
  1866             gpg.gpgme_op_keylist_end(session->ctx);
  1867             gpg.gpgme_release(import_ctx);
  1868             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1869             return PEP_UNKNOWN_ERROR;
  1870         };
  1871     } while (gpgme_error != GPG_ERR_EOF);
  1872 
  1873     gpg.gpgme_op_keylist_end(session->ctx);
  1874     gpg.gpgme_release(import_ctx);
  1875     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1876     return PEP_STATUS_OK;
  1877 }
  1878 
  1879 static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
  1880                             stringlist_t** keylist,
  1881                             int private_only) {
  1882     gpgme_error_t gpgme_error;
  1883     gpgme_key_t key;
  1884 
  1885     assert(session);
  1886     assert(keylist);
  1887 
  1888     *keylist = NULL;
  1889 
  1890     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
  1891     gpgme_error = _GPGERR(gpgme_error);
  1892     switch (gpgme_error) {
  1893         case GPG_ERR_NO_ERROR:
  1894             break;
  1895         case GPG_ERR_INV_VALUE:
  1896             assert(0);
  1897             return PEP_UNKNOWN_ERROR;
  1898         default:
  1899             gpg.gpgme_op_keylist_end(session->ctx);
  1900             return PEP_GET_KEY_FAILED;
  1901     };
  1902 
  1903     stringlist_t *_keylist = new_stringlist(NULL);
  1904     stringlist_t *_k = _keylist;
  1905 
  1906     do {
  1907         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1908         gpgme_error = _GPGERR(gpgme_error);
  1909         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1910         switch (gpgme_error) {
  1911             case GPG_ERR_EOF:
  1912                 break;
  1913             case GPG_ERR_NO_ERROR:
  1914                 assert(key);
  1915                 assert(key->subkeys);
  1916                 if(!key->subkeys)
  1917                     break;
  1918                 assert(key->uids);
  1919                 gpgme_user_id_t kuid = key->uids;
  1920                 // check that at least one uid's email matches pattern exactly,
  1921                 // modulo the email-diff heuristic
  1922                 while(kuid) {
  1923                     if((pattern == NULL) ||
  1924                        (strstr(pattern, "@") == NULL) || // not an email
  1925                        (kuid->email && _email_heuristic_match(kuid->email, pattern)))
  1926                     { 
  1927                         char *fpr = key->subkeys->fpr;
  1928                         assert(fpr);
  1929                         _k = stringlist_add(_k, fpr);
  1930                         assert(_k);
  1931                         if (_k == NULL){
  1932                             free_stringlist(_keylist);
  1933                             gpg.gpgme_op_keylist_end(session->ctx);
  1934                             return PEP_OUT_OF_MEMORY;
  1935                         }
  1936                         break;
  1937                     }
  1938                     kuid = kuid->next;
  1939                 }
  1940                 break;
  1941             case GPG_ERR_ENOMEM:
  1942                 free_stringlist(_keylist);
  1943                 gpg.gpgme_op_keylist_end(session->ctx);
  1944                 return PEP_OUT_OF_MEMORY;
  1945             default:
  1946                 gpg.gpgme_op_keylist_end(session->ctx);
  1947                 return PEP_UNKNOWN_ERROR;
  1948         };
  1949     } while (gpgme_error != GPG_ERR_EOF);
  1950 
  1951     gpg.gpgme_op_keylist_end(session->ctx);
  1952     if (_keylist->value == NULL) {
  1953         free_stringlist(_keylist);
  1954         _keylist = NULL;
  1955         
  1956         if (pattern != NULL) {
  1957             // If match failed, check to see if we've got a dotted address in the pattern.
  1958             // (last chance of the heuristic, really)
  1959             // If so, try again without any dots.
  1960             const char* dotpos = strstr(pattern, ".");
  1961             const char* atpos = strstr(pattern, "@");
  1962             if (dotpos && atpos && (dotpos < atpos)) {
  1963                 char* undotted = _undot_address(pattern);
  1964                 if (undotted) {
  1965                     PEP_STATUS status = _pgp_search_keys(session, undotted,
  1966                                                          keylist, private_only);
  1967                     free(undotted);
  1968                     return status;
  1969                 }
  1970             }
  1971         }
  1972     }    
  1973     
  1974     *keylist = _keylist;
  1975     return PEP_STATUS_OK;
  1976 }
  1977 
  1978 PEP_STATUS pgp_find_keys(
  1979     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1980     )
  1981 {
  1982     return _pgp_search_keys(session, pattern, keylist, 0);
  1983 }
  1984 
  1985 PEP_STATUS pgp_find_private_keys(
  1986     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1987 )
  1988 {
  1989     return _pgp_search_keys(session, pattern, keylist, 1);
  1990 }
  1991 
  1992 // this function is delivering a list of triples with fpr, email, name of all
  1993 // ultimatedly trusted private keys
  1994 
  1995 PEP_STATUS pgp_find_trusted_private_keys(
  1996         PEP_SESSION session, stringlist_t **keylist
  1997     )
  1998 {
  1999     assert(session && keylist);
  2000     if (!session || !keylist)
  2001         return PEP_ILLEGAL_VALUE;
  2002 
  2003     *keylist = NULL;
  2004 
  2005     gpgme_key_t key;
  2006     gpgme_error_t gpgme_error;
  2007 
  2008     stringlist_t *private_keylist = NULL;
  2009     PEP_STATUS status = pgp_find_private_keys(session, NULL, &private_keylist);
  2010     if (status)
  2011         return status;
  2012     if (!private_keylist || !private_keylist->value)
  2013         return status;
  2014 
  2015     stringlist_t *result_list = new_stringlist(NULL);
  2016     if (!result_list)
  2017         return PEP_OUT_OF_MEMORY;
  2018     stringlist_t *_result_list = result_list;
  2019 
  2020     stringlist_t *keylist_curr;
  2021     for (keylist_curr = private_keylist; keylist_curr && keylist_curr->value; keylist_curr = keylist_curr->next) {
  2022         // a. get key data
  2023         gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
  2024         gpgme_error = _GPGERR(gpgme_error);
  2025         assert(gpgme_error != GPG_ERR_ENOMEM);
  2026         switch (gpgme_error) {
  2027             case GPG_ERR_NO_ERROR:
  2028                 break;
  2029             case GPG_ERR_EOF:
  2030                 status = PEP_KEY_NOT_FOUND;
  2031                 break;
  2032             case GPG_ERR_INV_VALUE:
  2033                 status = PEP_ILLEGAL_VALUE;
  2034                 break;
  2035             case GPG_ERR_AMBIGUOUS_NAME:
  2036                 status = PEP_KEY_HAS_AMBIG_NAME;
  2037                 break;
  2038             case GPG_ERR_ENOMEM:
  2039                 free_stringlist(result_list);
  2040                 free_stringlist(private_keylist);
  2041                 return PEP_OUT_OF_MEMORY;
  2042             default:
  2043                 assert(0);
  2044                 status = PEP_UNKNOWN_ERROR;
  2045         }
  2046         if (key && gpgme_error == GPG_ERR_NO_ERROR) {
  2047             if (key->revoked || key->disabled) {
  2048                 status = PEP_KEY_UNSUITABLE;
  2049             }
  2050             else {
  2051                 if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
  2052                     if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
  2053                             key->uids && key->uids->email && key->uids->name) { 
  2054                         _result_list = stringlist_add(_result_list, key->fpr);
  2055                         if (!_result_list) {
  2056                             free_stringlist(result_list);
  2057                             free_stringlist(private_keylist);
  2058                             return PEP_OUT_OF_MEMORY;
  2059                         }
  2060                         _result_list = stringlist_add(_result_list, key->uids->email);
  2061                         if (!_result_list) {
  2062                             free_stringlist(result_list);
  2063                             free_stringlist(private_keylist);
  2064                             return PEP_OUT_OF_MEMORY;
  2065                         }
  2066                         _result_list = stringlist_add(_result_list, key->uids->name);
  2067                         if (!_result_list) {
  2068                             free_stringlist(result_list);
  2069                             free_stringlist(private_keylist);
  2070                             return PEP_OUT_OF_MEMORY;
  2071                         }
  2072                     }
  2073                 }
  2074             }
  2075         }
  2076     }
  2077 
  2078     free_stringlist(private_keylist);
  2079     *keylist = result_list;
  2080     return PEP_STATUS_OK;
  2081 }
  2082 
  2083 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  2084 {
  2085     gpgme_error_t gpgme_error;
  2086 
  2087     assert(session);
  2088     assert(pattern);
  2089 
  2090     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  2091         GPGME_EXPORT_MODE_EXTERN, NULL);
  2092     gpgme_error = _GPGERR(gpgme_error);
  2093     assert(gpgme_error != GPG_ERR_INV_VALUE);
  2094     if (gpgme_error == GPG_ERR_NO_ERROR)
  2095         return PEP_STATUS_OK;
  2096     else
  2097         return PEP_CANNOT_SEND_KEY;
  2098 }
  2099 
  2100 PEP_STATUS pgp_get_key_rating(
  2101     PEP_SESSION session,
  2102     const char *fpr,
  2103     PEP_comm_type *comm_type
  2104     )
  2105 {
  2106     PEP_STATUS status = PEP_STATUS_OK;
  2107     gpgme_error_t gpgme_error;
  2108     gpgme_key_t key;
  2109 
  2110     assert(session);
  2111     assert(fpr);
  2112     assert(comm_type);
  2113 
  2114     *comm_type = PEP_ct_unknown;
  2115 
  2116     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  2117     gpgme_error = _GPGERR(gpgme_error);
  2118     switch (gpgme_error) {
  2119     case GPG_ERR_NO_ERROR:
  2120         break;
  2121     case GPG_ERR_INV_VALUE:
  2122         assert(0);
  2123         return PEP_UNKNOWN_ERROR;
  2124     default:
  2125         return PEP_GET_KEY_FAILED;
  2126     };
  2127 
  2128     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  2129     gpgme_error = _GPGERR(gpgme_error);
  2130     assert(gpgme_error != GPG_ERR_INV_VALUE);
  2131 
  2132     if (key == NULL) {
  2133         gpg.gpgme_op_keylist_end(session->ctx);
  2134         return PEP_KEY_NOT_FOUND;
  2135     }
  2136 
  2137     switch (key->protocol) {
  2138     case GPGME_PROTOCOL_OpenPGP:
  2139     case GPGME_PROTOCOL_DEFAULT:
  2140         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  2141         break;
  2142     case GPGME_PROTOCOL_CMS:
  2143         *comm_type = PEP_ct_CMS_unconfirmed;
  2144         break;
  2145     default:
  2146         *comm_type = PEP_ct_unknown;
  2147         gpg.gpgme_op_keylist_end(session->ctx);
  2148         return PEP_STATUS_OK;
  2149     }
  2150     
  2151 
  2152     // N.B. and FIXME 
  2153     // We could get a key with a bad signing subkey and a good encryption
  2154     // subkey. For now, we reject this, because it forces large changes in
  2155     // how we rate keys. It's on the to-do list, but it's low priority.
  2156     // We don't really want to be doing much for tinkered keys in the first
  2157     // place.
  2158     switch (gpgme_error) {
  2159     case GPG_ERR_EOF:
  2160         break;
  2161     case GPG_ERR_NO_ERROR:
  2162         assert(key);
  2163         assert(key->subkeys);
  2164         
  2165         // is main key expired or revoked? If so, we can cut short this nonsense.
  2166         if (key->invalid)
  2167             *comm_type = PEP_ct_key_b0rken;
  2168         else if (key->revoked)
  2169             *comm_type = PEP_ct_key_revoked;            
  2170         else if (key->expired)
  2171             *comm_type = PEP_ct_key_expired;
  2172         else if (!key->subkeys)
  2173             *comm_type = PEP_ct_key_b0rken;
  2174         else {
  2175             // Ok, so we now need to check subkeys. Normally, we could just
  2176             // shortcut this by looking at key->can_sign and key->can_encrypt,
  2177             // but we want the REASON we can't use a key, so this gets ugly.
  2178             PEP_comm_type max_comm_type = *comm_type;
  2179 
  2180             // NOTE: 
  2181             // PEP_ct_pEp functions here as an unreachable top;
  2182             // it is impossible on just a key.
  2183             // IF THIS CHANGES, we must choose something else.
  2184             PEP_comm_type worst_sign = PEP_ct_pEp;
  2185             PEP_comm_type worst_enc = PEP_ct_pEp;
  2186 
  2187             PEP_comm_type error_sign = PEP_ct_unknown;
  2188             PEP_comm_type error_enc = PEP_ct_unknown;
  2189 
  2190             // We require that the underlying client NOT force-use expired or revoked
  2191             // subkeys instead of a valid one.
  2192             //
  2193             // So here we check all the subkeys; we make note of the existence
  2194             // of an expired, revoked, or invalid subkey, in case there is no
  2195             // other alternative (we want to return useful information).
  2196             // At the same time, we try to evaluate the least strong useable keys 
  2197             // for signing and encryption. If there is a useable one of both,
  2198             // the key comm_type corresponds to the lesser of these two least strong
  2199             // keys
  2200             for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  2201                 
  2202                 // Only evaluate signing keys or encryption keys
  2203                 if (sk->can_sign || sk->can_encrypt) {
  2204                     PEP_comm_type curr_sign = PEP_ct_no_encryption;
  2205                     PEP_comm_type curr_enc = PEP_ct_no_encryption;
  2206 
  2207 #ifdef GPGME_PK_ECC                    
  2208                     if ((sk->pubkey_algo != GPGME_PK_ECC && sk->length < 1024) 
  2209                         || (sk->pubkey_algo == GPGME_PK_ECC && sk->length < 160)) {
  2210 #else
  2211                     if (sk->length < 1024) {                        
  2212 #endif                        
  2213                         if (sk->can_sign)
  2214                             curr_sign = PEP_ct_key_too_short;
  2215                         if (sk->can_encrypt)                               
  2216                             curr_enc = PEP_ct_key_too_short;
  2217                     }
  2218                     else if 
  2219                         (
  2220                             (((sk->pubkey_algo == GPGME_PK_RSA)
  2221                                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  2222                                 || (sk->pubkey_algo == GPGME_PK_RSA_S))
  2223                                 && sk->length == 1024)
  2224 #ifdef GPGME_PK_ECC                    
  2225                             || (sk->pubkey_algo == GPGME_PK_ECC
  2226                                 && sk->length == 160)
  2227 #endif                             
  2228                         ) {
  2229                         if (sk->can_sign)
  2230                             curr_sign = PEP_ct_OpenPGP_weak_unconfirmed;
  2231                         if (sk->can_encrypt)                               
  2232                             curr_enc = PEP_ct_OpenPGP_weak_unconfirmed;
  2233                     }
  2234                     else {
  2235                         if (sk->can_sign)
  2236                             curr_sign = max_comm_type;
  2237                         if (sk->can_encrypt)
  2238                             curr_enc = max_comm_type;
  2239                     }
  2240                     if (sk->invalid) {
  2241                         if (sk->can_sign)
  2242                             curr_sign = PEP_ct_key_b0rken;
  2243                         if (sk->can_encrypt)                               
  2244                             curr_enc = PEP_ct_key_b0rken;
  2245                     }
  2246                     if (sk->expired) {
  2247                         if (sk->can_sign)
  2248                             curr_sign = PEP_ct_key_expired;
  2249                         if (sk->can_encrypt)                               
  2250                             curr_enc = PEP_ct_key_expired;
  2251                     }
  2252                     if (sk->revoked) {
  2253                         if (sk->can_sign)
  2254                             curr_sign = PEP_ct_key_revoked;
  2255                         if (sk->can_encrypt)                               
  2256                             curr_enc = PEP_ct_key_revoked;
  2257                     }
  2258                     switch (curr_sign) {
  2259                         case PEP_ct_key_b0rken:
  2260                         case PEP_ct_key_expired:
  2261                         case PEP_ct_key_revoked:
  2262                             error_sign = curr_sign;
  2263                             break;
  2264                         default:    
  2265                             if (sk->can_sign)
  2266                                 worst_sign = _MIN(curr_sign, worst_sign);
  2267                             break;
  2268                     }
  2269                     switch (curr_enc) {
  2270                         case PEP_ct_key_b0rken:
  2271                         case PEP_ct_key_expired:
  2272                         case PEP_ct_key_revoked:
  2273                             error_sign = curr_sign;
  2274                             break;
  2275                         default:    
  2276                             if (sk->can_encrypt)
  2277                                 worst_enc = _MIN(curr_enc, worst_enc);
  2278                             break;
  2279                     }                    
  2280                 }    
  2281             }
  2282             if (worst_enc == PEP_ct_pEp ||
  2283                 worst_sign == PEP_ct_pEp) {
  2284                 // No valid key was found for one or both; return a useful 
  2285                 // error comm_type
  2286                 PEP_comm_type error_ct = _MAX(error_enc, error_sign);    
  2287                 *comm_type = (error_ct == PEP_ct_unknown ? PEP_ct_key_b0rken : error_ct);
  2288             }
  2289             else {
  2290                 *comm_type = _MIN(max_comm_type, _MIN(worst_sign, worst_enc));
  2291             }                
  2292         }
  2293         break;
  2294     case GPG_ERR_ENOMEM:
  2295         gpg.gpgme_op_keylist_end(session->ctx);
  2296         *comm_type = PEP_ct_unknown;
  2297         return PEP_OUT_OF_MEMORY;
  2298     default:
  2299         gpg.gpgme_op_keylist_end(session->ctx);
  2300         return PEP_UNKNOWN_ERROR;
  2301     };
  2302 
  2303     gpg.gpgme_op_keylist_end(session->ctx);
  2304 
  2305     return status;
  2306 }
  2307 
  2308 
  2309 static ssize_t _nullwriter(
  2310         void *_handle,
  2311         const void *buffer,
  2312         size_t size
  2313     )
  2314 {
  2315     return size;
  2316 }
  2317 
  2318 typedef struct _replace_only_uid_state {
  2319     enum {
  2320         replace_uid_command = 0,
  2321         replace_uid_realname,
  2322         replace_uid_email,
  2323         replace_uid_comment,
  2324         replace_uid_adduid_ok,
  2325         replace_uid_select_for_delete,
  2326         replace_uid_delete,
  2327         replace_uid_delete_confirm,
  2328         replace_uid_select_for_trust,
  2329         replace_uid_trust,
  2330         replace_uid_trust_ultimate,
  2331         replace_uid_trust_ultimate_confirm,
  2332         replace_uid_quit,
  2333         replace_uid_save_okay,
  2334         replace_uid_exit,
  2335         replace_uid_error = -1
  2336     } state;
  2337 const char *realname;
  2338 const char *email;
  2339 } replace_only_uid_state;
  2340 
  2341 
  2342 static gpgme_error_t replace_only_uid_fsm(
  2343     void *_handle,
  2344     gpgme_status_code_t statuscode,
  2345     const char *args,
  2346     int fd
  2347 )
  2348 {
  2349     replace_only_uid_state *handle = _handle;
  2350         
  2351     switch (handle->state) {
  2352         case replace_uid_command:
  2353             if (statuscode == GPGME_STATUS_GET_LINE) {
  2354                 assert(strcmp(args, "keyedit.prompt") == 0);
  2355                 if (strcmp(args, "keyedit.prompt")) {
  2356                     handle->state = replace_uid_error;
  2357                     return GPG_ERR_GENERAL;
  2358                 }
  2359                 gpg.gpgme_io_write(fd, "adduid\n", 7);
  2360                 handle->state = replace_uid_realname;
  2361             }
  2362             break;
  2363             
  2364         case replace_uid_realname:
  2365             if (statuscode == GPGME_STATUS_GET_LINE) {
  2366                 assert(strcmp(args, "keygen.name") == 0);
  2367                 assert(handle->realname);
  2368                 if (strcmp(args, "keygen.name") || !handle->realname) {
  2369                     handle->state = replace_uid_error;
  2370                     return GPG_ERR_GENERAL;
  2371                 }
  2372                 size_t realname_strlen = strlen(handle->realname);
  2373                 char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
  2374                 if (!realname) {
  2375                     handle->state = replace_uid_error;
  2376                     return GPG_ERR_ENOMEM;
  2377                 }
  2378                 strlcpy(realname, handle->realname, realname_strlen + 1);
  2379                 realname[realname_strlen] = '\n';
  2380                 gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
  2381                 handle->state = replace_uid_email;
  2382                 free(realname);
  2383             }
  2384             break;
  2385             
  2386         case replace_uid_email:
  2387             if (statuscode == GPGME_STATUS_GET_LINE) {
  2388                 assert(strcmp(args, "keygen.email") == 0);
  2389                 assert(handle->email);
  2390                 if (strcmp(args, "keygen.email") || !handle->email) {
  2391                     handle->state = replace_uid_error;
  2392                     return GPG_ERR_GENERAL;
  2393                 }
  2394                 size_t email_strlen = strlen(handle->email);
  2395                 char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
  2396                 if (!email) {
  2397                     handle->state = replace_uid_error;
  2398                     return GPG_ERR_ENOMEM;
  2399                 }
  2400                 strlcpy(email, handle->email, email_strlen + 1);
  2401                 email[email_strlen] = '\n';
  2402                 gpg.gpgme_io_write(fd, email, email_strlen + 1);
  2403                 handle->state = replace_uid_comment;
  2404                 free(email);
  2405             }
  2406             break;
  2407 
  2408         case replace_uid_comment:
  2409             if (statuscode == GPGME_STATUS_GET_LINE) {
  2410                 assert(strcmp(args, "keygen.comment") == 0);
  2411                 if (strcmp(args, "keygen.comment") || !handle->email) {
  2412                     handle->state = replace_uid_error;
  2413                     return GPG_ERR_GENERAL;
  2414                 }
  2415                 gpg.gpgme_io_write(fd, "\n", 1);
  2416                 //handle->state = replace_uid_adduid_ok;
  2417                 handle->state = replace_uid_select_for_delete;
  2418             }
  2419             break;
  2420 /*
  2421         case replace_uid_adduid_ok:
  2422             if (statuscode == GPGME_STATUS_GET_LINE) {
  2423                 assert(strcmp(args, "keygen.userid.cmd") == 0);
  2424                 if (strcmp(args, "keygen.userid.cmd")) {
  2425                     handle->state = replace_uid_error;
  2426                     return GPG_ERR_GENERAL;
  2427                 }
  2428                 gpg.gpgme_io_write(fd, "O\n", 2);
  2429                 handle->state = replace_uid_select_for_delete;
  2430             }
  2431             break;
  2432 	    */
  2433 
  2434         case replace_uid_select_for_delete:
  2435             if (statuscode == GPGME_STATUS_GET_LINE) {
  2436                 assert(strcmp(args, "keyedit.prompt") == 0);
  2437                 if (strcmp(args, "keyedit.prompt")) {
  2438                     handle->state = replace_uid_error;
  2439                     return GPG_ERR_GENERAL;
  2440                 }
  2441                 gpg.gpgme_io_write(fd, "uid 1\n", 6);
  2442                 handle->state = replace_uid_delete;
  2443             }
  2444             break;
  2445 
  2446         case replace_uid_delete:
  2447             if (statuscode == GPGME_STATUS_GET_LINE) {
  2448                 assert(strcmp(args, "keyedit.prompt") == 0);
  2449                 if (strcmp(args, "keyedit.prompt")) {
  2450                     handle->state = replace_uid_error;
  2451                     return GPG_ERR_GENERAL;
  2452                 }
  2453                 gpg.gpgme_io_write(fd, "deluid\n", 7);
  2454                 handle->state = replace_uid_delete_confirm;
  2455             }
  2456             break;
  2457 
  2458         case replace_uid_delete_confirm:
  2459             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2460                 assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
  2461                 if (strcmp(args, "keyedit.remove.uid.okay")) {
  2462                     handle->state = replace_uid_error;
  2463                     return GPG_ERR_GENERAL;
  2464                 }
  2465                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2466                 handle->state = replace_uid_select_for_trust;
  2467             }
  2468             break;
  2469 
  2470         case replace_uid_select_for_trust:
  2471             if (statuscode == GPGME_STATUS_GET_LINE) {
  2472                 assert(strcmp(args, "keyedit.prompt") == 0);
  2473                 if (strcmp(args, "keyedit.prompt")) {
  2474                     handle->state = replace_uid_error;
  2475                     return GPG_ERR_GENERAL;
  2476                 }
  2477                 gpg.gpgme_io_write(fd, "uid 1\n", 6);
  2478                 handle->state = replace_uid_trust;
  2479             }
  2480             break;
  2481 
  2482         case replace_uid_trust:
  2483             if (statuscode == GPGME_STATUS_GET_LINE) {
  2484                 assert(strcmp(args, "keyedit.prompt") == 0);
  2485                 if (strcmp(args, "keyedit.prompt")) {
  2486                     handle->state = replace_uid_error;
  2487                     return GPG_ERR_GENERAL;
  2488                 }
  2489                 gpg.gpgme_io_write(fd, "trust\n", 6);
  2490                 handle->state = replace_uid_trust_ultimate;
  2491             }
  2492             break;
  2493 
  2494         case replace_uid_trust_ultimate:
  2495             if (statuscode == GPGME_STATUS_GET_LINE) {
  2496                 assert(strcmp(args, "edit_ownertrust.value") == 0);
  2497                 if (strcmp(args, "edit_ownertrust.value")) {
  2498                     handle->state = replace_uid_error;
  2499                     return GPG_ERR_GENERAL;
  2500                 }
  2501                 gpg.gpgme_io_write(fd, "5\n", 2);
  2502                 handle->state = replace_uid_trust_ultimate_confirm;
  2503             }
  2504             break;
  2505 
  2506         case replace_uid_trust_ultimate_confirm:
  2507             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2508                 assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
  2509                 if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
  2510                     handle->state = replace_uid_error;
  2511                     return GPG_ERR_GENERAL;
  2512                 }
  2513                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2514                 handle->state = replace_uid_quit;
  2515             }
  2516             break;
  2517 
  2518         case replace_uid_quit:
  2519             if (statuscode == GPGME_STATUS_GET_LINE) {
  2520                 assert(strcmp(args, "keyedit.prompt") == 0);
  2521                 if (strcmp(args, "keyedit.prompt")) {
  2522                     handle->state = replace_uid_error;
  2523                     return GPG_ERR_GENERAL;
  2524                 }
  2525                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2526                 handle->state = replace_uid_save_okay;
  2527             }
  2528             break;
  2529 
  2530         case replace_uid_save_okay:
  2531             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2532                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2533                 if (strcmp(args, "keyedit.save.okay")) {
  2534                     handle->state = replace_uid_error;
  2535                     return GPG_ERR_GENERAL;
  2536                 }
  2537                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2538                 handle->state = replace_uid_exit;
  2539             }
  2540             break;
  2541 
  2542         case replace_uid_exit:
  2543             break;
  2544 
  2545         case replace_uid_error:
  2546             return GPG_ERR_GENERAL;
  2547             
  2548         default:
  2549             break;
  2550     }
  2551     return GPG_ERR_NO_ERROR;
  2552 }
  2553 
  2554 PEP_STATUS pgp_replace_only_uid(
  2555         PEP_SESSION session,
  2556         const char* fpr,
  2557         const char* realname,
  2558         const char* email
  2559     )
  2560 {
  2561     PEP_STATUS status = PEP_STATUS_OK;
  2562     gpgme_error_t gpgme_error;
  2563     gpgme_key_t key;
  2564     gpgme_data_t output;
  2565     replace_only_uid_state handle;
  2566 
  2567     assert(session);
  2568     assert(fpr);
  2569     assert(realname);
  2570     assert(email);
  2571     
  2572     memset(&handle, 0, sizeof(replace_only_uid_state));
  2573     handle.realname = realname;
  2574     handle.email = email;
  2575 
  2576     status = find_single_key(session, fpr, &key);
  2577     if (status != PEP_STATUS_OK)
  2578         return status;
  2579 
  2580     struct gpgme_data_cbs data_cbs;
  2581     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2582     data_cbs.write = _nullwriter;
  2583     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2584 
  2585     gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, replace_only_uid_fsm, &handle,
  2586             output));
  2587     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2588     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2589         status = PEP_CANNOT_EDIT_KEY;
  2590     }
  2591 
  2592     gpg.gpgme_data_release(output);
  2593     gpg.gpgme_key_unref(key);
  2594 
  2595     return status;
  2596 }
  2597 
  2598 
  2599 typedef struct _renew_state {
  2600     enum {
  2601         renew_command = 0,
  2602         renew_date,
  2603         renew_secret_key,
  2604         renew_command2,
  2605         renew_date2,
  2606         renew_quit,
  2607         renew_save,
  2608         renew_exit,
  2609         renew_error = -1
  2610     } state;
  2611     const char *date_ref;
  2612 } renew_state;
  2613 
  2614 static gpgme_error_t renew_fsm(
  2615         void *_handle,
  2616         gpgme_status_code_t statuscode,
  2617         const char *args,
  2618         int fd
  2619     )
  2620 {
  2621     renew_state *handle = _handle;
  2622 
  2623     switch (handle->state) {
  2624         case renew_command:
  2625             if (statuscode == GPGME_STATUS_GET_LINE) {
  2626                 assert(strcmp(args, "keyedit.prompt") == 0);
  2627                 if (strcmp(args, "keyedit.prompt")) {
  2628                     handle->state = renew_error;
  2629                     return GPG_ERR_GENERAL;
  2630                 }
  2631                 gpg.gpgme_io_write(fd, "expire\n", 7);
  2632                 handle->state = renew_date;
  2633             }
  2634             break;
  2635 
  2636         case renew_date:
  2637             if (statuscode == GPGME_STATUS_GET_LINE) {
  2638                 assert(strcmp(args, "keygen.valid") == 0);
  2639                 if (strcmp(args, "keygen.valid")) {
  2640                     handle->state = renew_error;
  2641                     return GPG_ERR_GENERAL;
  2642                 }
  2643                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2644                 handle->state = renew_secret_key;
  2645             }
  2646             break;
  2647 
  2648         case renew_secret_key:
  2649             if (statuscode == GPGME_STATUS_GET_LINE) {
  2650                 assert(strcmp(args, "keyedit.prompt") == 0);
  2651                 if (strcmp(args, "keyedit.prompt")) {
  2652                     handle->state = renew_error;
  2653                     return GPG_ERR_GENERAL;
  2654                 }
  2655                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  2656                 handle->state = renew_command2;
  2657             }
  2658             break;
  2659 
  2660         case renew_command2:
  2661             if (statuscode == GPGME_STATUS_GET_LINE) {
  2662                 assert(strcmp(args, "keyedit.prompt") == 0);
  2663                 if (strcmp(args, "keyedit.prompt")) {
  2664                     handle->state = renew_error;
  2665                     return GPG_ERR_GENERAL;
  2666                 }
  2667                 gpg.gpgme_io_write(fd, "expire\n", 7);
  2668                 handle->state = renew_date2;
  2669             }
  2670             break;
  2671 
  2672         case renew_date2:
  2673             if (statuscode == GPGME_STATUS_GET_LINE) {
  2674                 assert(strcmp(args, "keygen.valid") == 0);
  2675                 if (strcmp(args, "keygen.valid")) {
  2676                     handle->state = renew_error;
  2677                     return GPG_ERR_GENERAL;
  2678                 }
  2679                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2680                 handle->state = renew_quit;
  2681             }
  2682             break;
  2683 
  2684         case renew_quit:
  2685             if (statuscode == GPGME_STATUS_GET_LINE) {
  2686                 assert(strcmp(args, "keyedit.prompt") == 0);
  2687                 if (strcmp(args, "keyedit.prompt")) {
  2688                     handle->state = renew_error;
  2689                     return GPG_ERR_GENERAL;
  2690                 }
  2691                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2692                 handle->state = renew_save;
  2693             }
  2694             break;
  2695 
  2696         case renew_save:
  2697             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2698                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2699                 if (strcmp(args, "keyedit.save.okay")) {
  2700                     handle->state = renew_error;
  2701                     return GPG_ERR_GENERAL;
  2702                 }
  2703                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2704                 handle->state = renew_exit;
  2705             }
  2706             break;
  2707 
  2708         case renew_exit:
  2709             break;
  2710 
  2711         case renew_error:
  2712             return GPG_ERR_GENERAL;
  2713     }
  2714 
  2715     return GPG_ERR_NO_ERROR;
  2716 }
  2717 
  2718 
  2719 PEP_STATUS pgp_renew_key(
  2720         PEP_SESSION session,
  2721         const char *fpr,
  2722         const timestamp *ts
  2723     )
  2724 {
  2725     PEP_STATUS status = PEP_STATUS_OK;
  2726     gpgme_error_t gpgme_error;
  2727     gpgme_key_t key;
  2728     gpgme_data_t output;
  2729     renew_state handle;
  2730     char date_text[12];
  2731 
  2732     assert(session);
  2733     assert(fpr);
  2734 
  2735     memset(&handle, 0, sizeof(renew_state));
  2736     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  2737             ts->tm_mon + 1, ts->tm_mday);
  2738     handle.date_ref = date_text;
  2739 
  2740     status = find_single_key(session, fpr, &key);
  2741     if (status != PEP_STATUS_OK)
  2742         return status;
  2743 
  2744     struct gpgme_data_cbs data_cbs;
  2745     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2746     data_cbs.write = _nullwriter;
  2747     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2748 
  2749     gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  2750             output));
  2751     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2752     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2753         status = PEP_CANNOT_EDIT_KEY;
  2754     }
  2755 
  2756     gpg.gpgme_data_release(output);
  2757     gpg.gpgme_key_unref(key);
  2758 
  2759     return status;
  2760 }
  2761 
  2762 typedef struct _revoke_state {
  2763     enum {
  2764         revoke_command = 0,
  2765         revoke_approve,
  2766         revoke_reason_code,
  2767         revoke_reason_text,
  2768         revoke_reason_ok,
  2769         revoke_quit,
  2770         revoke_save,
  2771         revoke_exit,
  2772         revoke_error = -1
  2773     } state;
  2774     const char *reason_ref;
  2775 } revoke_state;
  2776 
  2777 
  2778 /*** unused?
  2779 static bool isemptystring(const char *str)
  2780 {
  2781     if (str == NULL)
  2782         return true;
  2783 
  2784     for (; str; str++) {
  2785         if (*str != ' ' && *str != '\t' && *str != '\n')
  2786             return false;
  2787     }
  2788 
  2789     return true;
  2790 }
  2791 ***/
  2792 
  2793 
  2794 static gpgme_error_t revoke_fsm(
  2795         void *_handle,
  2796         gpgme_status_code_t statuscode,
  2797         const char *args,
  2798         int fd
  2799     )
  2800 {
  2801     revoke_state *handle = _handle;
  2802 
  2803     switch (handle->state) {
  2804         case revoke_command:
  2805             if (statuscode == GPGME_STATUS_GET_LINE) {
  2806                 assert(strcmp(args, "keyedit.prompt") == 0);
  2807                 if (strcmp(args, "keyedit.prompt")) {
  2808                     handle->state = revoke_error;
  2809                     return GPG_ERR_GENERAL;
  2810                 }
  2811                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  2812                 handle->state = revoke_approve;
  2813             }
  2814             break;
  2815 
  2816         case revoke_approve:
  2817             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2818                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  2819                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  2820                     handle->state = revoke_error;
  2821                     return GPG_ERR_GENERAL;
  2822                 }
  2823                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2824                 handle->state = revoke_reason_code;
  2825             }
  2826             break;
  2827 
  2828         case revoke_reason_code:
  2829             if (statuscode == GPGME_STATUS_GET_LINE) {
  2830                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  2831                 if (strcmp(args, "ask_revocation_reason.code")) {
  2832                     handle->state = revoke_error;
  2833                     return GPG_ERR_GENERAL;
  2834                 }
  2835                 gpg.gpgme_io_write(fd, "1\n", 2);
  2836                 handle->state = revoke_reason_text;
  2837             }
  2838             break;
  2839 
  2840         case revoke_reason_text:
  2841             if (statuscode == GPGME_STATUS_GET_LINE) {
  2842                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  2843                 if (strcmp(args, "ask_revocation_reason.text")) {
  2844                     handle->state = revoke_error;
  2845                     return GPG_ERR_GENERAL;
  2846                 }
  2847                 // BUG: issues when reason given
  2848                 // Assertion failed: (gpg->cmd.code), function command_handler,
  2849                 // file engine-gpg.c, line 662.
  2850                 //
  2851                 // if (isemptystring(handle->reason_ref)) {
  2852                     gpg.gpgme_io_write(fd, "\n", 1);
  2853                 // }
  2854                 // else {
  2855                 //     size_t len = strlen(handle->reason_ref);
  2856                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  2857                 //     if (handle->reason_ref[len - 1] == '\n')
  2858                 //         gpg.gpgme_io_write(fd, "\n", 1);
  2859                 //     else
  2860                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  2861                 // }
  2862                 handle->state = revoke_reason_ok;
  2863             }
  2864             break;
  2865 
  2866         case revoke_reason_ok:
  2867             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2868                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  2869                 if (strcmp(args, "ask_revocation_reason.okay")) {
  2870                     handle->state = revoke_error;
  2871                     return GPG_ERR_GENERAL;
  2872                 }
  2873                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2874                 handle->state = revoke_quit;
  2875             }
  2876             break;
  2877 
  2878         case revoke_quit:
  2879             if (statuscode == GPGME_STATUS_GET_LINE) {
  2880                 assert(strcmp(args, "keyedit.prompt") == 0);
  2881                 if (strcmp(args, "keyedit.prompt")) {
  2882                     handle->state = revoke_error;
  2883                     return GPG_ERR_GENERAL;
  2884                 }
  2885                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2886                 handle->state = revoke_save;
  2887             }
  2888             break;
  2889 
  2890         case revoke_save:
  2891             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2892                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2893                 if (strcmp(args, "keyedit.save.okay")) {
  2894                     handle->state = revoke_error;
  2895                     return GPG_ERR_GENERAL;
  2896                 }
  2897                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2898                 handle->state = revoke_exit;
  2899             }
  2900             break;
  2901 
  2902         case revoke_exit:
  2903             break;
  2904 
  2905         case revoke_error:
  2906             return GPG_ERR_GENERAL;
  2907     }
  2908 
  2909     return GPG_ERR_NO_ERROR;
  2910 }
  2911 
  2912 PEP_STATUS pgp_revoke_key(
  2913         PEP_SESSION session,
  2914         const char *fpr,
  2915         const char *reason
  2916     )
  2917 {
  2918     PEP_STATUS status = PEP_STATUS_OK;
  2919     gpgme_error_t gpgme_error;
  2920     gpgme_key_t key;
  2921     gpgme_data_t output;
  2922     revoke_state handle;
  2923 
  2924     assert(session);
  2925     assert(fpr);
  2926 
  2927     memset(&handle, 0, sizeof(revoke_state));
  2928     handle.reason_ref = reason;
  2929 
  2930     status = find_single_key(session, fpr, &key);
  2931     if (status != PEP_STATUS_OK)
  2932         return status;
  2933 
  2934     struct gpgme_data_cbs data_cbs;
  2935     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2936     data_cbs.write = _nullwriter;
  2937     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2938 
  2939     gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  2940             output));
  2941     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2942     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2943         status = PEP_CANNOT_EDIT_KEY;
  2944     }
  2945 
  2946     gpg.gpgme_data_release(output);
  2947     gpg.gpgme_key_unref(key);
  2948 
  2949     return status;
  2950 }
  2951 
  2952 PEP_STATUS pgp_key_expired(
  2953         PEP_SESSION session,
  2954         const char *fpr,
  2955         const time_t when,
  2956         bool *expired
  2957     )
  2958 {
  2959     PEP_STATUS status = PEP_STATUS_OK;
  2960     gpgme_key_t key;
  2961 
  2962     assert(session);
  2963     assert(fpr);
  2964     assert(expired);
  2965 
  2966     *expired = false;
  2967 
  2968     status = find_single_key(session, fpr, &key);
  2969     if (status != PEP_STATUS_OK)
  2970         return status;
  2971 
  2972     if ((key && key->expired) ||
  2973         (key && key->subkeys && key->subkeys->expired))
  2974     {
  2975         // Already marked expired
  2976         *expired = 1;
  2977     }
  2978     else if (key)
  2979     {
  2980         // Detect if will be expired
  2981         // i.e. Check that keys capabilities will
  2982         // not be expired at given time.
  2983         gpgme_subkey_t _sk;
  2984         bool crt_available = false;
  2985         bool sgn_available = false;
  2986         bool enc_available = false;
  2987         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  2988             if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
  2989                                                           // Also, zero means "does not expire"
  2990             {
  2991                 if (_sk->can_certify) crt_available = true;
  2992                 if (_sk->can_sign) sgn_available = true;
  2993                 if (_sk->can_encrypt) enc_available = true;
  2994                 // Authenticate is not used here.
  2995             }
  2996         }
  2997         if(!(crt_available && sgn_available && enc_available))
  2998         {
  2999             *expired = 1;
  3000         }
  3001     }
  3002     else
  3003     {
  3004         status = PEP_KEY_NOT_FOUND;
  3005     }
  3006 
  3007     gpg.gpgme_key_unref(key);
  3008     return status;
  3009 }
  3010 
  3011 PEP_STATUS pgp_key_revoked(
  3012         PEP_SESSION session,
  3013         const char *fpr,
  3014         bool *revoked
  3015     )
  3016 {
  3017     PEP_STATUS status = PEP_STATUS_OK;
  3018     gpgme_key_t key;
  3019 
  3020     assert(session);
  3021     assert(fpr);
  3022     assert(revoked);
  3023 
  3024     *revoked = false;
  3025 
  3026     status = find_single_key(session, fpr, &key);
  3027     if (status != PEP_STATUS_OK)
  3028         return status;
  3029 
  3030     if (key && key->subkeys)
  3031     {
  3032         *revoked = key->subkeys->revoked;
  3033     }
  3034     else
  3035     {
  3036         status = PEP_KEY_NOT_FOUND;
  3037     }
  3038 
  3039     gpg.gpgme_key_unref(key);
  3040     return status;
  3041 }
  3042 
  3043 PEP_STATUS pgp_key_created(
  3044         PEP_SESSION session,
  3045         const char *fpr,
  3046         time_t *created
  3047     )
  3048 {
  3049     PEP_STATUS status = PEP_STATUS_OK;
  3050     gpgme_key_t key;
  3051 
  3052     assert(session);
  3053     assert(fpr);
  3054     assert(created);
  3055 
  3056     *created = 0;
  3057 
  3058     status = find_single_key(session, fpr, &key);
  3059     if (status != PEP_STATUS_OK)
  3060         return status;
  3061 
  3062     if (key && key->subkeys)
  3063     {
  3064         *created = (time_t) key->subkeys->timestamp;
  3065     }
  3066     else
  3067     {
  3068         status = PEP_KEY_NOT_FOUND;
  3069     }
  3070 
  3071     gpg.gpgme_key_unref(key);
  3072     return status;
  3073 }
  3074 
  3075 PEP_STATUS pgp_binary(const char **path)
  3076 {
  3077     assert(path);
  3078     if (path == NULL)
  3079         return PEP_ILLEGAL_VALUE;
  3080 
  3081     *path = NULL;
  3082 
  3083     gpgme_engine_info_t info;
  3084     gpgme_error_t err = _GPGERR(gpg.gpgme_get_engine_info(&info));
  3085     assert(err == GPG_ERR_NO_ERROR);
  3086     if (err != GPG_ERR_NO_ERROR)
  3087         return PEP_OUT_OF_MEMORY;
  3088 
  3089     *path = info->file_name;
  3090 
  3091     return PEP_STATUS_OK;
  3092 }
  3093 
  3094 PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
  3095         bool *has_private) {
  3096     PEP_STATUS status = PEP_STATUS_OK;
  3097     gpgme_key_t output_key;
  3098     gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
  3099     *has_private = false;
  3100     switch (_GPGERR(gpgerr)) {
  3101         case GPG_ERR_EOF:
  3102         case GPG_ERR_INV_VALUE:
  3103             status = PEP_KEY_NOT_FOUND;
  3104             break;
  3105         case GPG_ERR_AMBIGUOUS_NAME:
  3106             status = PEP_KEY_HAS_AMBIG_NAME;
  3107             break;
  3108         case GPG_ERR_NO_ERROR:
  3109             *has_private = true;
  3110             gpg.gpgme_key_release(output_key);
  3111             break;
  3112         case GPG_ERR_ENOMEM:
  3113             status = PEP_OUT_OF_MEMORY;
  3114             break;
  3115         default:
  3116             status = PEP_UNKNOWN_ERROR;
  3117             break;
  3118     }
  3119     return status;
  3120 }
  3121 
  3122 PEP_STATUS pgp_config_cipher_suite(PEP_SESSION session,
  3123         PEP_CIPHER_SUITE suite)
  3124 {
  3125     // functionaliy unsupported; use gpg.conf
  3126 
  3127     switch (suite) {
  3128         case PEP_CIPHER_SUITE_DEFAULT:
  3129             return PEP_STATUS_OK;
  3130         default:
  3131             return PEP_CANNOT_CONFIG;
  3132     }
  3133 }