src/pgp_gpg.c
author Neal H. Walfield <neal@pep.foundation>
Sat, 01 Jun 2019 21:24:45 +0200
branchsync
changeset 3799 5f0990b24c15
parent 3699 e2aa6fdbd20b
permissions -rw-r--r--
Add benchmark

- By default, this is just a normal test.

- Defining LOG=1 in the source changes it to a benchmark. See the
file for documentation.
     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                         case GPG_ERR_BAD_SIGNATURE:
   682                             result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   683                             //result = PEP_DECRYPT_BAD_SIGNATURE;
   684                             break;
   685                         case GPG_ERR_SIG_EXPIRED:
   686                         case GPG_ERR_KEY_EXPIRED:
   687                         case GPG_ERR_NO_PUBKEY:
   688                             k = stringlist_add(k, gpgme_signature->fpr);
   689                             if (k == NULL) {
   690                                 free_stringlist(_keylist);
   691                                 if (recipient_keylist)
   692                                     free_stringlist(recipient_keylist);
   693                                 gpg.gpgme_data_release(plain);
   694                                 gpg.gpgme_data_release(cipher);
   695                                 free(_buffer);
   696                                 return PEP_OUT_OF_MEMORY;
   697                             }
   698                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   699                                 result = PEP_DECRYPTED;
   700                             break;
   701                         case GPG_ERR_GENERAL:
   702                             break;
   703                         default:
   704                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   705                                 result = PEP_DECRYPTED;
   706                             break;
   707                         }
   708                     } while ((gpgme_signature = gpgme_signature->next));
   709                 }
   710                 else {
   711                     result = PEP_DECRYPTED;
   712                 }
   713 
   714                 if (result == PEP_DECRYPTED_AND_VERIFIED
   715                     || result == PEP_DECRYPTED) {
   716                     *ptext = _buffer;
   717                     *psize = reading;
   718                     (*ptext)[*psize] = 0; // safeguard for naive users
   719                     *keylist = _keylist;
   720                     if (recipient_keylist) {
   721                         if (!_keylist)
   722                             *keylist = new_stringlist(""); // no sig
   723                         if (!(*keylist)) {
   724                             free_stringlist(_keylist);
   725                             if (recipient_keylist)
   726                                 free_stringlist(recipient_keylist);
   727                             gpg.gpgme_data_release(plain);
   728                             gpg.gpgme_data_release(cipher);
   729                             free(_buffer);
   730                             return PEP_OUT_OF_MEMORY;
   731                         }
   732                         stringlist_append(*keylist, recipient_keylist);
   733                     }
   734                 }
   735                 else {
   736                     free_stringlist(_keylist);
   737                     if (recipient_keylist)
   738                         free_stringlist(recipient_keylist);
   739                     free(_buffer);
   740                 }
   741                 break;
   742             }
   743             case GPG_ERR_BAD_PASSPHRASE:
   744             case GPG_ERR_NO_DATA:
   745                 result = PEP_DECRYPT_NO_KEY;
   746                 break;
   747             case GPG_ERR_DECRYPT_FAILED:
   748             default:
   749             {
   750                 gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   751                 result = PEP_DECRYPT_NO_KEY;
   752 
   753                 if (gpgme_decrypt_result != NULL) {
   754                     if (gpgme_decrypt_result->unsupported_algorithm)
   755                         *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   756                     else
   757                         *keylist = new_stringlist("");
   758                     assert(*keylist);
   759                     if (*keylist == NULL) {
   760                         result = PEP_OUT_OF_MEMORY;
   761                         break;
   762                     }
   763                 }
   764             }
   765         }
   766         break;
   767 
   768     default:
   769         result = PEP_DECRYPT_WRONG_FORMAT;
   770     }
   771 
   772     gpg.gpgme_data_release(plain);
   773     gpg.gpgme_data_release(cipher);
   774     return result;
   775 }
   776 
   777 PEP_STATUS pgp_verify_text(
   778     PEP_SESSION session, const char *text, size_t size,
   779     const char *signature, size_t sig_size, stringlist_t **keylist
   780     )
   781 {
   782     PEP_STATUS result;
   783     gpgme_error_t gpgme_error;
   784     gpgme_data_t d_text, d_sig;
   785     stringlist_t *_keylist;
   786 
   787     assert(session);
   788     assert(text);
   789     assert(size);
   790     assert(signature);
   791     assert(sig_size);
   792     assert(keylist);
   793 
   794     *keylist = NULL;
   795 
   796     gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   797     gpgme_error = _GPGERR(gpgme_error);
   798     assert(gpgme_error == GPG_ERR_NO_ERROR);
   799     if (gpgme_error != GPG_ERR_NO_ERROR) {
   800         if (gpgme_error == GPG_ERR_ENOMEM)
   801             return PEP_OUT_OF_MEMORY;
   802         else
   803             return PEP_UNKNOWN_ERROR;
   804     }
   805 
   806     gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   807     gpgme_error = _GPGERR(gpgme_error);
   808     assert(gpgme_error == GPG_ERR_NO_ERROR);
   809     if (gpgme_error != GPG_ERR_NO_ERROR) {
   810         gpg.gpgme_data_release(d_text);
   811         if (gpgme_error == GPG_ERR_ENOMEM)
   812             return PEP_OUT_OF_MEMORY;
   813         else
   814             return PEP_UNKNOWN_ERROR;
   815     }
   816 
   817     gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
   818     gpgme_error = _GPGERR(gpgme_error);
   819     assert(gpgme_error != GPG_ERR_INV_VALUE);
   820 
   821     switch (gpgme_error) {
   822     case GPG_ERR_NO_ERROR:
   823     {
   824         gpgme_verify_result_t gpgme_verify_result;
   825         gpgme_signature_t gpgme_signature;
   826 
   827         gpgme_verify_result =
   828             gpg.gpgme_op_verify_result(session->ctx);
   829         assert(gpgme_verify_result);
   830         gpgme_signature = gpgme_verify_result->signatures;
   831 
   832         if (gpgme_signature) {
   833             stringlist_t *k;
   834             _keylist = new_stringlist(NULL);
   835             assert(_keylist);
   836             if (_keylist == NULL) {
   837                 gpg.gpgme_data_release(d_text);
   838                 gpg.gpgme_data_release(d_sig);
   839                 return PEP_OUT_OF_MEMORY;
   840             }
   841             k = _keylist;
   842 
   843             result = PEP_VERIFIED;
   844             do {
   845                 gpgme_key_t key;
   846                 memset(&key,0,sizeof(key));
   847 
   848                 // GPGME may give subkey's fpr instead of primary key's fpr.
   849                 // Therefore we ask for the primary fingerprint instead
   850                 // we assume that gpgme_get_key can find key by subkey's fpr
   851                 gpgme_error = gpg.gpgme_get_key(session->ctx,
   852                     gpgme_signature->fpr, &key, 0);
   853                 gpgme_error = _GPGERR(gpgme_error);
   854                 assert(gpgme_error != GPG_ERR_ENOMEM);
   855                 if (gpgme_error == GPG_ERR_ENOMEM) {
   856                     free_stringlist(_keylist);
   857                     gpg.gpgme_data_release(d_text);
   858                     gpg.gpgme_data_release(d_sig);
   859                     return PEP_OUT_OF_MEMORY;
   860                 }
   861                 // Primary key is given as the first subkey
   862                 if (gpgme_error == GPG_ERR_NO_ERROR &&
   863                     key && key->subkeys && key->subkeys->fpr
   864                     && key->subkeys->fpr[0])
   865                 {
   866                     k = stringlist_add(k, key->subkeys->fpr);
   867 
   868                     gpg.gpgme_key_unref(key);
   869 
   870                     if (k == NULL) {
   871                         free_stringlist(_keylist);
   872                         gpg.gpgme_data_release(d_text);
   873                         gpg.gpgme_data_release(d_sig);
   874                         return PEP_OUT_OF_MEMORY;
   875                     }
   876                 }
   877                 else {
   878                     result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   879                     break;
   880                 }
   881 
   882                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   883                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   884                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   885                         if (result == PEP_VERIFIED
   886                             || result == PEP_VERIFIED_AND_TRUSTED)
   887                             result = PEP_UNENCRYPTED;
   888                     }
   889                     else {
   890                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   891                         break;
   892                     }
   893                 }
   894                 else {
   895                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   896                         if (result == PEP_VERIFIED)
   897                             result = PEP_VERIFIED_AND_TRUSTED;
   898                     }
   899                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   900                         // good
   901                     }
   902                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   903                         result = PEP_VERIFY_NO_KEY;
   904                     }
   905                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   906                         if (result == PEP_VERIFIED
   907                             || result == PEP_VERIFIED_AND_TRUSTED)
   908                             result = PEP_UNENCRYPTED;
   909                     }
   910                     else {
   911                         // do nothing
   912                     }
   913                 }
   914             } while ((gpgme_signature = gpgme_signature->next));
   915             *keylist = _keylist;
   916         }
   917         else {
   918             result = PEP_UNENCRYPTED;
   919         }
   920         break;
   921     }
   922         break;
   923     case GPG_ERR_NO_DATA:
   924         result = PEP_DECRYPT_WRONG_FORMAT;
   925         break;
   926     case GPG_ERR_INV_VALUE:
   927     default:
   928         result = PEP_UNKNOWN_ERROR;
   929         break;
   930     }
   931 
   932     gpg.gpgme_data_release(d_text);
   933     gpg.gpgme_data_release(d_sig);
   934 
   935     return result;
   936 }
   937 
   938 PEP_STATUS pgp_sign_only(    
   939     PEP_SESSION session, const char* fpr, const char *ptext,
   940     size_t psize, char **stext, size_t *ssize
   941 )
   942 {
   943     assert(session);
   944     assert(fpr && fpr[0]);
   945     assert(ptext);
   946     assert(psize);
   947     assert(stext);
   948     assert(ssize);
   949 
   950     PEP_STATUS result;
   951     gpgme_error_t gpgme_error;
   952     gpgme_data_t plain, signed_text;
   953     gpgme_key_t* signer_key_ptr;
   954 
   955     gpgme_sig_mode_t sign_mode = GPGME_SIG_MODE_DETACH;
   956        
   957     *stext = NULL;
   958     *ssize = 0;
   959 
   960     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
   961     gpgme_error = _GPGERR(gpgme_error);
   962     assert(gpgme_error == GPG_ERR_NO_ERROR);
   963     if (gpgme_error != GPG_ERR_NO_ERROR) {
   964         if (gpgme_error == GPG_ERR_ENOMEM)
   965             return PEP_OUT_OF_MEMORY;
   966         else
   967             return PEP_UNKNOWN_ERROR;
   968     }
   969 
   970     gpgme_error = gpg.gpgme_data_new(&signed_text);
   971     gpgme_error = _GPGERR(gpgme_error);
   972     assert(gpgme_error == GPG_ERR_NO_ERROR);
   973     if (gpgme_error != GPG_ERR_NO_ERROR) {
   974         gpg.gpgme_data_release(plain);
   975         if (gpgme_error == GPG_ERR_ENOMEM)
   976             return PEP_OUT_OF_MEMORY;
   977         else
   978             return PEP_UNKNOWN_ERROR;
   979     }
   980 
   981     signer_key_ptr = calloc(1, sizeof(gpgme_key_t));   
   982     assert(signer_key_ptr);
   983     if (signer_key_ptr == NULL) {
   984         gpg.gpgme_data_release(plain);
   985         gpg.gpgme_data_release(signed_text);
   986         return PEP_OUT_OF_MEMORY;
   987     }
   988 
   989     gpg.gpgme_signers_clear(session->ctx);
   990 
   991     // Get signing key
   992     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr,
   993                                     signer_key_ptr, 0);
   994     gpgme_error = _GPGERR(gpgme_error);
   995     assert(gpgme_error != GPG_ERR_ENOMEM);
   996     gpgme_error_t _gpgme_error;
   997     
   998     switch (gpgme_error) {
   999     case GPG_ERR_ENOMEM:
  1000         gpg.gpgme_key_unref(*signer_key_ptr);
  1001         free(signer_key_ptr);
  1002         gpg.gpgme_data_release(plain);
  1003         gpg.gpgme_data_release(signed_text);
  1004         return PEP_OUT_OF_MEMORY;
  1005     case GPG_ERR_NO_ERROR:
  1006         _gpgme_error = gpg.gpgme_signers_add(session->ctx, *signer_key_ptr);
  1007         _gpgme_error = _GPGERR(_gpgme_error);
  1008         assert(_gpgme_error == GPG_ERR_NO_ERROR);
  1009         break;
  1010     case GPG_ERR_EOF:
  1011         gpg.gpgme_key_unref(*signer_key_ptr);
  1012         free(signer_key_ptr);
  1013         gpg.gpgme_data_release(plain);
  1014         gpg.gpgme_data_release(signed_text);
  1015         return PEP_KEY_NOT_FOUND;
  1016     case GPG_ERR_AMBIGUOUS_NAME:
  1017         gpg.gpgme_key_unref(*signer_key_ptr);
  1018         free(signer_key_ptr);
  1019         gpg.gpgme_data_release(plain);
  1020         gpg.gpgme_data_release(signed_text);
  1021         return PEP_KEY_HAS_AMBIG_NAME;
  1022     default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
  1023         // FPR is not a fingerprint or key ID
  1024         gpg.gpgme_key_unref(*signer_key_ptr);
  1025         free(signer_key_ptr);
  1026         gpg.gpgme_data_release(plain);
  1027         gpg.gpgme_data_release(signed_text);
  1028         return PEP_GET_KEY_FAILED;
  1029     }
  1030  
  1031     gpgme_error = gpg.gpgme_op_sign(session->ctx, plain, signed_text, sign_mode);
  1032 
  1033     gpgme_error = _GPGERR(gpgme_error);
  1034     switch (gpgme_error) {
  1035     case GPG_ERR_NO_ERROR:
  1036     {
  1037         char *_buffer = NULL;
  1038         size_t reading;
  1039         size_t length = gpg.gpgme_data_seek(signed_text, 0, SEEK_END);
  1040         assert(length != -1);
  1041         gpg.gpgme_data_seek(signed_text, 0, SEEK_SET);
  1042 
  1043         // TODO: make things less memory consuming
  1044         // the following algorithm allocates a buffer for the complete text
  1045 
  1046         _buffer = malloc(length + 1);
  1047         assert(_buffer);
  1048         if (_buffer == NULL) {
  1049             gpg.gpgme_key_unref(*signer_key_ptr);
  1050             free(signer_key_ptr);
  1051             gpg.gpgme_data_release(plain);
  1052             gpg.gpgme_data_release(signed_text);
  1053             return PEP_OUT_OF_MEMORY;
  1054         }
  1055 
  1056         reading = gpg.gpgme_data_read(signed_text, _buffer, length);
  1057         assert(length == reading);
  1058 
  1059         *stext = _buffer;
  1060         *ssize = reading;
  1061         (*stext)[*ssize] = 0; // safeguard for naive users
  1062         result = PEP_STATUS_OK;
  1063         break;
  1064     }
  1065     default:
  1066         result = PEP_UNKNOWN_ERROR;
  1067     }
  1068 
  1069     gpg.gpgme_key_unref(*signer_key_ptr);
  1070     free(signer_key_ptr);
  1071     gpg.gpgme_data_release(plain);
  1072     gpg.gpgme_data_release(signed_text);
  1073     return result;   
  1074 }
  1075 
  1076 static PEP_STATUS pgp_encrypt_sign_optional(    
  1077     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1078     size_t psize, char **ctext, size_t *csize, bool sign
  1079 )
  1080 {
  1081     PEP_STATUS result;
  1082     gpgme_error_t gpgme_error;
  1083     gpgme_data_t plain, cipher;
  1084     gpgme_key_t *rcpt;
  1085     gpgme_encrypt_flags_t flags;
  1086     const stringlist_t *_keylist;
  1087     int i, j;
  1088 
  1089     assert(session);
  1090     assert(keylist);
  1091     assert(ptext);
  1092     assert(psize);
  1093     assert(ctext);
  1094     assert(csize);
  1095 
  1096     *ctext = NULL;
  1097     *csize = 0;
  1098 
  1099     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
  1100     gpgme_error = _GPGERR(gpgme_error);
  1101     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1102     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1103         if (gpgme_error == GPG_ERR_ENOMEM)
  1104             return PEP_OUT_OF_MEMORY;
  1105         else
  1106             return PEP_UNKNOWN_ERROR;
  1107     }
  1108 
  1109     gpgme_error = gpg.gpgme_data_new(&cipher);
  1110     gpgme_error = _GPGERR(gpgme_error);
  1111     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1112     if (gpgme_error != GPG_ERR_NO_ERROR) {
  1113         gpg.gpgme_data_release(plain);
  1114         if (gpgme_error == GPG_ERR_ENOMEM)
  1115             return PEP_OUT_OF_MEMORY;
  1116         else
  1117             return PEP_UNKNOWN_ERROR;
  1118     }
  1119 
  1120     rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
  1121     assert(rcpt);
  1122     if (rcpt == NULL) {
  1123         gpg.gpgme_data_release(plain);
  1124         gpg.gpgme_data_release(cipher);
  1125         return PEP_OUT_OF_MEMORY;
  1126     }
  1127 
  1128     gpg.gpgme_signers_clear(session->ctx);
  1129 
  1130     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
  1131         assert(_keylist->value);
  1132         gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
  1133             &rcpt[i], 0);
  1134         gpgme_error = _GPGERR(gpgme_error);
  1135         assert(gpgme_error != GPG_ERR_ENOMEM);
  1136 
  1137         switch (gpgme_error) {
  1138         case GPG_ERR_ENOMEM:
  1139             for (j = 0; j<i; j++)
  1140                 gpg.gpgme_key_unref(rcpt[j]);
  1141             free(rcpt);
  1142             gpg.gpgme_data_release(plain);
  1143             gpg.gpgme_data_release(cipher);
  1144             return PEP_OUT_OF_MEMORY;
  1145         case GPG_ERR_NO_ERROR:
  1146             if (i == 0 && sign) {
  1147                 gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
  1148                 _gpgme_error = _GPGERR(_gpgme_error);
  1149                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
  1150             }
  1151             break;
  1152         case GPG_ERR_EOF:
  1153             for (j = 0; j<i; j++)
  1154                 gpg.gpgme_key_unref(rcpt[j]);
  1155             free(rcpt);
  1156             gpg.gpgme_data_release(plain);
  1157             gpg.gpgme_data_release(cipher);
  1158             return PEP_KEY_NOT_FOUND;
  1159         case GPG_ERR_AMBIGUOUS_NAME:
  1160             for (j = 0; j<i; j++)
  1161                 gpg.gpgme_key_unref(rcpt[j]);
  1162             free(rcpt);
  1163             gpg.gpgme_data_release(plain);
  1164             gpg.gpgme_data_release(cipher);
  1165             return PEP_KEY_HAS_AMBIG_NAME;
  1166         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
  1167             // FPR is not a fingerprint or key ID
  1168             for (j = 0; j<i; j++)
  1169                 gpg.gpgme_key_unref(rcpt[j]);
  1170             free(rcpt);
  1171             gpg.gpgme_data_release(plain);
  1172             gpg.gpgme_data_release(cipher);
  1173             return PEP_GET_KEY_FAILED;
  1174         }
  1175     }
  1176 
  1177     // TODO: remove that and replace with proper key management
  1178     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
  1179     
  1180     if (sign) {
  1181         gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
  1182             plain, cipher);
  1183     }
  1184     else {
  1185         gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
  1186             plain, cipher);
  1187     }
  1188     
  1189     gpgme_error = _GPGERR(gpgme_error);
  1190     switch (gpgme_error) {
  1191     case GPG_ERR_NO_ERROR:
  1192     {
  1193         char *_buffer = NULL;
  1194         size_t reading;
  1195         size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
  1196         assert(length != -1);
  1197         gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
  1198 
  1199         // TODO: make things less memory consuming
  1200         // the following algorithm allocates a buffer for the complete text
  1201 
  1202         _buffer = malloc(length + 1);
  1203         assert(_buffer);
  1204         if (_buffer == NULL) {
  1205             for (j = 0; j<stringlist_length(keylist); j++)
  1206                 gpg.gpgme_key_unref(rcpt[j]);
  1207             free(rcpt);
  1208             gpg.gpgme_data_release(plain);
  1209             gpg.gpgme_data_release(cipher);
  1210             return PEP_OUT_OF_MEMORY;
  1211         }
  1212 
  1213         reading = gpg.gpgme_data_read(cipher, _buffer, length);
  1214         assert(length == reading);
  1215 
  1216         *ctext = _buffer;
  1217         *csize = reading;
  1218         (*ctext)[*csize] = 0; // safeguard for naive users
  1219         result = PEP_STATUS_OK;
  1220         break;
  1221     }
  1222     default:
  1223         result = PEP_UNKNOWN_ERROR;
  1224     }
  1225 
  1226     for (j = 0; j<stringlist_length(keylist); j++)
  1227         gpg.gpgme_key_unref(rcpt[j]);
  1228     free(rcpt);
  1229     gpg.gpgme_data_release(plain);
  1230     gpg.gpgme_data_release(cipher);
  1231     return result;
  1232 }
  1233 
  1234 PEP_STATUS pgp_encrypt_only(
  1235     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1236     size_t psize, char **ctext, size_t *csize
  1237     )
  1238 {
  1239     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1240         psize, ctext, csize, false);
  1241 }
  1242 
  1243 PEP_STATUS pgp_encrypt_and_sign(
  1244     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1245     size_t psize, char **ctext, size_t *csize
  1246     )
  1247 {
  1248     return pgp_encrypt_sign_optional(session, keylist, ptext,
  1249         psize, ctext, csize, true);
  1250 }
  1251 
  1252 
  1253 static PEP_STATUS find_single_key(
  1254         PEP_SESSION session,
  1255         const char *fpr,
  1256         gpgme_key_t *key
  1257     )
  1258 {
  1259     gpgme_error_t gpgme_error;
  1260 
  1261     *key = NULL;
  1262 
  1263 //    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1264 
  1265     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, key, 0);
  1266 
  1267     gpgme_error = _GPGERR(gpgme_error);
  1268     switch (gpgme_error) {
  1269     case GPG_ERR_NO_ERROR:
  1270         break;
  1271     case GPG_ERR_INV_VALUE:
  1272         assert(0);
  1273         return PEP_UNKNOWN_ERROR;
  1274     default:
  1275         return PEP_GET_KEY_FAILED;
  1276     };
  1277 
  1278 //    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1279 //    gpgme_error = _GPGERR(gpgme_error);
  1280 //    assert(gpgme_error != GPG_ERR_INV_VALUE);
  1281 
  1282 //    gpg.gpgme_op_keylist_end(session->ctx);
  1283 
  1284     return PEP_STATUS_OK;
  1285 }
  1286 
  1287 
  1288 static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
  1289     PEP_STATUS status = PEP_VERSION_MISMATCH;
  1290 
  1291     if (identity && identity->address) {
  1292 #ifdef GPGME_VERSION_NUMBER 
  1293 #if (GPGME_VERSION_NUMBER >= 0x010700)
  1294         gpgme_error_t gpgme_error;
  1295         int userid_size = strlen(identity->address) + 1;
  1296         char* userid = (char*)(calloc(1, userid_size));
  1297         if (!userid)
  1298             return PEP_OUT_OF_MEMORY;
  1299         strlcpy(userid, identity->address, userid_size);
  1300         gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
  1301                                              0, 31536000, NULL, 
  1302                                              GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE);
  1303         gpgme_error = _GPGERR(gpgme_error);
  1304 
  1305         free(userid);
  1306 
  1307         if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
  1308             switch (gpgme_error) {
  1309                 case GPG_ERR_NO_ERROR:
  1310                     break;
  1311                 case GPG_ERR_INV_VALUE:
  1312                     return PEP_ILLEGAL_VALUE;
  1313                 default:
  1314                     return PEP_CANNOT_CREATE_KEY;
  1315             }
  1316 
  1317             /* This is the same regardless of whether we got it from genkey or createkey */
  1318             gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1319             assert(gpgme_genkey_result);
  1320             assert(gpgme_genkey_result->fpr);
  1321 
  1322             char* fpr = strdup(gpgme_genkey_result->fpr);
  1323             gpgme_key_t key;
  1324             PEP_STATUS key_status = find_single_key(session, fpr, &key);
  1325             if (!key || key_status != PEP_STATUS_OK)
  1326                 return PEP_CANNOT_CREATE_KEY;
  1327             
  1328             gpgme_error = gpg.gpgme_op_createsubkey(session->ctx, key, 
  1329                                                     "RSA", 0, 
  1330                                                     31536000, GPGME_CREATE_NOPASSWD 
  1331                                                     | GPGME_CREATE_ENCR);
  1332 
  1333             switch (gpgme_error) {
  1334                 case GPG_ERR_NO_ERROR:
  1335                     break;
  1336                 case GPG_ERR_INV_VALUE:
  1337                     return PEP_ILLEGAL_VALUE;
  1338                 case GPG_ERR_GENERAL:
  1339                     return PEP_CANNOT_CREATE_KEY;
  1340                 default:
  1341                     assert(0);
  1342                     return PEP_UNKNOWN_ERROR;
  1343             }
  1344             
  1345             free(identity->fpr);
  1346             identity->fpr = fpr;
  1347             if (identity->fpr == NULL)
  1348                 return PEP_OUT_OF_MEMORY;
  1349 
  1350 //            gpg.gpgme_key_unref(key);
  1351             
  1352             status = pgp_replace_only_uid(session, fpr,
  1353                         identity->username, identity->address);
  1354         }
  1355 #endif
  1356 #endif
  1357     }
  1358     
  1359     return status;
  1360 }
  1361 
  1362 PEP_STATUS pgp_generate_keypair(
  1363     PEP_SESSION session, pEp_identity *identity
  1364     )
  1365 {
  1366     assert(session);
  1367     assert(identity);
  1368     assert(identity->address);
  1369     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1370     assert(identity->username);
  1371 
  1372     PEP_STATUS status = _pgp_createkey(session, identity);
  1373     
  1374     if (status != PEP_VERSION_MISMATCH)
  1375         return status;
  1376         
  1377     gpgme_error_t gpgme_error;
  1378     char *parms;
  1379     const char *template =
  1380         "<GnupgKeyParms format=\"internal\">\n"
  1381         "Key-Type: RSA\n"
  1382         "Key-Length: 4096\n"
  1383         "Subkey-Type: RSA\n"
  1384         "Subkey-Length: 4096\n"
  1385         "Name-Real: %s\n"
  1386         "Name-Email: %s\n"
  1387         /* "Passphrase: %s\n" */
  1388         "Expire-Date: 1y\n"
  1389         "</GnupgKeyParms>\n";
  1390     int result;
  1391 
  1392     parms = calloc(1, PARMS_MAX);
  1393     assert(parms);
  1394     if (parms == NULL)
  1395         return PEP_OUT_OF_MEMORY;
  1396 
  1397     result = snprintf(parms, PARMS_MAX, template, identity->username,
  1398         identity->address); // , session->passphrase);
  1399     assert(result < PARMS_MAX);
  1400     if (result >= PARMS_MAX) {
  1401         free(parms);
  1402         return PEP_BUFFER_TOO_SMALL;
  1403     }
  1404 
  1405     gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
  1406     gpgme_error = _GPGERR(gpgme_error);
  1407     free(parms);
  1408 
  1409     switch (gpgme_error) {
  1410     case GPG_ERR_NO_ERROR:
  1411         break;
  1412     case GPG_ERR_INV_VALUE:
  1413         return PEP_ILLEGAL_VALUE;
  1414     case GPG_ERR_GENERAL:
  1415         return PEP_CANNOT_CREATE_KEY;
  1416     default:
  1417         assert(0);
  1418         return PEP_UNKNOWN_ERROR;
  1419     }
  1420 
  1421     gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1422     assert(gpgme_genkey_result);
  1423     assert(gpgme_genkey_result->fpr);
  1424 
  1425     free(identity->fpr);
  1426     identity->fpr = strdup(gpgme_genkey_result->fpr);
  1427     if (identity->fpr == NULL)
  1428         return PEP_OUT_OF_MEMORY;
  1429 
  1430     return PEP_STATUS_OK;
  1431 }
  1432 
  1433 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
  1434 {
  1435     gpgme_error_t gpgme_error;
  1436     gpgme_key_t key;
  1437 
  1438     assert(session);
  1439     assert(fpr);
  1440 
  1441     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1442     gpgme_error = _GPGERR(gpgme_error);
  1443     assert(gpgme_error != GPG_ERR_ENOMEM);
  1444     switch (gpgme_error) {
  1445     case GPG_ERR_NO_ERROR:
  1446         break;
  1447     case GPG_ERR_EOF:
  1448         return PEP_KEY_NOT_FOUND;
  1449     case GPG_ERR_INV_VALUE:
  1450         return PEP_ILLEGAL_VALUE;
  1451     case GPG_ERR_AMBIGUOUS_NAME:
  1452         return PEP_KEY_HAS_AMBIG_NAME;
  1453     case GPG_ERR_ENOMEM:
  1454         return PEP_OUT_OF_MEMORY;
  1455     default:
  1456         assert(0);
  1457         return PEP_UNKNOWN_ERROR;
  1458     }
  1459 
  1460     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1461     gpgme_error = _GPGERR(gpgme_error);
  1462     gpg.gpgme_key_unref(key);
  1463     switch (gpgme_error) {
  1464     case GPG_ERR_NO_ERROR:
  1465         break;
  1466     case GPG_ERR_INV_VALUE:
  1467         assert(0);
  1468         return PEP_UNKNOWN_ERROR;
  1469     case GPG_ERR_NO_PUBKEY:
  1470         assert(0);
  1471         return PEP_KEY_NOT_FOUND;
  1472     case GPG_ERR_AMBIGUOUS_NAME:
  1473         assert(0);
  1474         return PEP_KEY_HAS_AMBIG_NAME;
  1475     default:
  1476         assert(0);
  1477         return PEP_UNKNOWN_ERROR;
  1478     }
  1479 
  1480     return PEP_STATUS_OK;
  1481 }
  1482 
  1483 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1484                               size_t size, identity_list **private_idents)
  1485 {
  1486     gpgme_error_t gpgme_error;
  1487     gpgme_data_t dh;
  1488 
  1489     assert(session);
  1490     assert(key_data);
  1491 
  1492     if(private_idents)
  1493         *private_idents = NULL;
  1494 
  1495     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1496     gpgme_error = _GPGERR(gpgme_error);
  1497     assert(gpgme_error != GPG_ERR_ENOMEM);
  1498     switch (gpgme_error) {
  1499     case GPG_ERR_NO_ERROR:
  1500         break;
  1501     case GPG_ERR_ENOMEM:
  1502         return PEP_OUT_OF_MEMORY;
  1503     case GPG_ERR_INV_VALUE:
  1504         assert(0);
  1505         return PEP_UNKNOWN_ERROR;
  1506     default:
  1507         assert(0);
  1508         return PEP_UNKNOWN_ERROR;
  1509     }
  1510 
  1511     gpgme_import_result_t gpgme_import_result;
  1512 
  1513     bool key_imported = false;
  1514     
  1515     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1516     gpgme_error = _GPGERR(gpgme_error);
  1517     switch (gpgme_error) {
  1518     case GPG_ERR_NO_ERROR:
  1519     
  1520         gpgme_import_result =
  1521             gpg.gpgme_op_import_result(session->ctx);
  1522         assert(gpgme_import_result);
  1523         if (!gpgme_import_result) {
  1524             gpg.gpgme_data_release(dh);
  1525             return PEP_UNKNOWN_ERROR;
  1526         }
  1527         // considered seems to only be true if it was 
  1528         // actually a key
  1529         if (gpgme_import_result->considered > 0)
  1530             // gpgme_import_result->imported > 0 ||
  1531             // gpgme_import_result->secret_imported > 0 ||
  1532             // gpgme_import_result->unchanged > 0 ||
  1533             // gpgme_import_result->secret_unchanged > 0)
  1534             key_imported = true;
  1535             
  1536         if(private_idents)
  1537         {
  1538             gpgme_import_status_t import;
  1539             for (import = gpgme_import_result->imports;
  1540                  import;
  1541                  import = import->next)
  1542              {
  1543                 if (import &&
  1544                     import->result == GPG_ERR_NO_ERROR &&
  1545                     import->status & GPGME_IMPORT_SECRET )
  1546                 {
  1547                     gpgme_key_t key = NULL;
  1548 
  1549                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1550                         import->fpr, &key, 0);
  1551                     gpgme_error = _GPGERR(gpgme_error);
  1552                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1553                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1554                         gpg.gpgme_data_release(dh);
  1555                         return PEP_OUT_OF_MEMORY;
  1556                     }
  1557 
  1558                     if (gpgme_error == GPG_ERR_NO_ERROR &&
  1559                         key && key->uids &&
  1560                         key->uids->email && key->uids->name)
  1561                     {
  1562                         pEp_identity *ident = new_identity(
  1563                              key->uids->email, import->fpr, NULL, key->uids->name);
  1564 
  1565                         gpg.gpgme_key_unref(key);
  1566 
  1567                         if (ident == NULL) {
  1568                             gpg.gpgme_data_release(dh);
  1569                             return PEP_OUT_OF_MEMORY;
  1570                         }
  1571 
  1572                         *private_idents = identity_list_add(*private_idents, ident);
  1573 
  1574                         if (*private_idents == NULL) {
  1575                             gpg.gpgme_data_release(dh);
  1576                             return PEP_OUT_OF_MEMORY;
  1577                         }
  1578                     }
  1579                     else
  1580                     {
  1581                         gpg.gpgme_key_unref(key);
  1582                         gpg.gpgme_data_release(dh);
  1583                         return PEP_UNKNOWN_ERROR;
  1584                     }
  1585                 }
  1586             }
  1587         }
  1588         break;
  1589     case GPG_ERR_INV_VALUE:
  1590         assert(0);
  1591         gpg.gpgme_data_release(dh);
  1592         return PEP_UNKNOWN_ERROR;
  1593     case GPG_ERR_NO_DATA:
  1594         gpg.gpgme_data_release(dh);
  1595         return PEP_ILLEGAL_VALUE;
  1596     default:
  1597         assert(0);
  1598         gpg.gpgme_data_release(dh);
  1599         return PEP_UNKNOWN_ERROR;
  1600     }
  1601 
  1602     gpg.gpgme_data_release(dh);
  1603     
  1604     if (key_imported)
  1605         return PEP_KEY_IMPORTED;
  1606         
  1607     return PEP_NO_KEY_IMPORTED;
  1608 }
  1609 
  1610 PEP_STATUS pgp_export_keydata(
  1611         PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
  1612         bool secret
  1613     )
  1614 {
  1615     gpgme_error_t gpgme_error;
  1616     gpgme_data_t dh;
  1617     size_t _size;
  1618     char *buffer = NULL;
  1619     int reading;
  1620 
  1621     assert(session);
  1622     assert(fpr);
  1623     assert(key_data);
  1624     assert(size);
  1625 
  1626     gpgme_error = gpg.gpgme_data_new(&dh);
  1627     gpgme_error = _GPGERR(gpgme_error);
  1628     assert(gpgme_error != GPG_ERR_ENOMEM);
  1629     switch (gpgme_error) {
  1630     case GPG_ERR_NO_ERROR:
  1631         break;
  1632     case GPG_ERR_ENOMEM:
  1633         return PEP_OUT_OF_MEMORY;
  1634     case GPG_ERR_INV_VALUE:
  1635         assert(0);
  1636         return PEP_UNKNOWN_ERROR;
  1637     default:
  1638         assert(0);
  1639         return PEP_UNKNOWN_ERROR;
  1640     }
  1641 
  1642     if (secret)
  1643         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1644             GPGME_EXPORT_MODE_SECRET, dh);
  1645     else
  1646         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1647             GPGME_EXPORT_MODE_MINIMAL, dh);
  1648     gpgme_error = _GPGERR(gpgme_error);
  1649     switch (gpgme_error) {
  1650     case GPG_ERR_NO_ERROR:
  1651         break;
  1652     case GPG_ERR_EOF:
  1653         gpg.gpgme_data_release(dh);
  1654         return PEP_KEY_NOT_FOUND;
  1655     case GPG_ERR_INV_VALUE:
  1656         assert(0);
  1657         gpg.gpgme_data_release(dh);
  1658         return PEP_UNKNOWN_ERROR;
  1659     default:
  1660         assert(0);
  1661         gpg.gpgme_data_release(dh);
  1662         return PEP_UNKNOWN_ERROR;
  1663     };
  1664 
  1665     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1666     assert(_size != -1);
  1667     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1668 
  1669     // Unfortunately, gpgme doesn't give us an error
  1670     // when no key is found, so we end up with an 
  1671     // empty string. So we need to do this:
  1672     if (_size == 0) {
  1673         *key_data = NULL;
  1674         *size = 0;
  1675         gpg.gpgme_data_release(dh);
  1676         return PEP_KEY_NOT_FOUND;
  1677     }
  1678         
  1679     buffer = malloc(_size + 1);
  1680     assert(buffer);
  1681     if (buffer == NULL) {
  1682         gpg.gpgme_data_release(dh);
  1683         return PEP_OUT_OF_MEMORY;
  1684     }
  1685 
  1686     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1687     assert(_size == reading);
  1688     if(_size != reading)
  1689         return PEP_CANNOT_EXPORT_KEY;
  1690 
  1691     // safeguard for the naive user
  1692     buffer[_size] = 0;
  1693 
  1694     *key_data = buffer;
  1695     *size = _size;
  1696 
  1697     gpg.gpgme_data_release(dh);
  1698     return PEP_STATUS_OK;
  1699 }
  1700 
  1701 PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
  1702                             stringpair_list_t** keyinfo_list)
  1703 {
  1704     gpgme_error_t gpgme_error;
  1705     assert(session);
  1706     assert(keyinfo_list);
  1707 
  1708     if (!session || !keyinfo_list)
  1709         return PEP_ILLEGAL_VALUE;
  1710 
  1711     *keyinfo_list = NULL;
  1712 
  1713     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1714     gpgme_error = _GPGERR(gpgme_error);
  1715 
  1716     switch(gpgme_error) {
  1717         case GPG_ERR_NO_ERROR:
  1718             break;
  1719         case GPG_ERR_INV_VALUE:
  1720             assert(0);
  1721             return PEP_UNKNOWN_ERROR;
  1722         default:
  1723             gpg.gpgme_op_keylist_end(session->ctx);
  1724             return PEP_GET_KEY_FAILED;
  1725     };
  1726 
  1727     gpgme_key_t key;
  1728     stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
  1729     stringpair_list_t* list_curr = _keyinfo_list;
  1730     stringpair_t* pair = NULL;
  1731 
  1732     do {
  1733         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1734         gpgme_error = _GPGERR(gpgme_error);
  1735 
  1736         switch(gpgme_error) {
  1737             case GPG_ERR_EOF:
  1738                 break;
  1739             case GPG_ERR_NO_ERROR:
  1740                 assert(key);
  1741                 assert(key->subkeys);
  1742                 if (!key || !key->subkeys)
  1743                     return PEP_GET_KEY_FAILED;
  1744 
  1745                 // first subkey is primary key
  1746                 char* fpr = key->subkeys->fpr;
  1747                 char* uid = key->uids->uid;
  1748 
  1749                 assert(fpr);
  1750                 assert(uid);
  1751                 if (!fpr)
  1752                     return PEP_GET_KEY_FAILED;
  1753 
  1754                 if (key->subkeys->revoked)
  1755                     continue;
  1756 
  1757                 pair = new_stringpair(fpr, uid);
  1758 
  1759                 assert(pair);
  1760 
  1761                 if (pair) {
  1762                     list_curr = stringpair_list_add(list_curr, pair);
  1763                     pair = NULL;
  1764 
  1765                     assert(list_curr);
  1766                     if (list_curr != NULL)
  1767                         break;
  1768                     else
  1769                         free_stringpair(pair);
  1770                 }
  1771                 // else fallthrough (list_curr or pair wasn't allocateable)
  1772             case GPG_ERR_ENOMEM:
  1773                 free_stringpair_list(_keyinfo_list);
  1774                 gpg.gpgme_op_keylist_end(session->ctx);
  1775                 return PEP_OUT_OF_MEMORY;
  1776             default:
  1777                 gpg.gpgme_op_keylist_end(session->ctx);
  1778                 return PEP_UNKNOWN_ERROR;
  1779         }
  1780     } while (gpgme_error != GPG_ERR_EOF);
  1781 
  1782     if (_keyinfo_list->value == NULL) {
  1783         free_stringpair_list(_keyinfo_list);
  1784         _keyinfo_list = NULL;
  1785     }
  1786 
  1787     *keyinfo_list = _keyinfo_list;
  1788 
  1789     return PEP_STATUS_OK;
  1790 }
  1791 
  1792 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1793     gpgme_keylist_mode_t add_mode)
  1794 {
  1795     gpgme_error_t gpgme_error;
  1796     gpgme_keylist_mode_t mode;
  1797 
  1798     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1799 
  1800     mode &= ~remove_mode;
  1801     mode |= add_mode;
  1802 
  1803     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1804     gpgme_error = _GPGERR(gpgme_error);
  1805     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1806 }
  1807 
  1808 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1809 {
  1810     gpgme_error_t gpgme_error;
  1811     gpgme_key_t key;
  1812 
  1813     assert(session);
  1814     assert(pattern);
  1815 
  1816     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1817 
  1818     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1819     gpgme_error = _GPGERR(gpgme_error);
  1820     switch (gpgme_error) {
  1821     case GPG_ERR_NO_ERROR:
  1822         break;
  1823     case GPG_ERR_INV_VALUE:
  1824         assert(0);
  1825         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1826         return PEP_UNKNOWN_ERROR;
  1827     default:
  1828         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1829         return PEP_GET_KEY_FAILED;
  1830     };
  1831 
  1832     gpgme_ctx_t import_ctx;
  1833     gpgme_error = gpg.gpgme_new(&import_ctx);
  1834     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1835 
  1836     do {
  1837         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1838         gpgme_error = _GPGERR(gpgme_error);
  1839         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1840         switch (gpgme_error) {
  1841         case GPG_ERR_EOF:
  1842             break;
  1843         case GPG_ERR_NO_ERROR:
  1844         {
  1845             gpgme_error_t gpgme_error;
  1846             gpgme_key_t keys[2];
  1847 
  1848             keys[0] = key;
  1849             keys[1] = NULL;
  1850 
  1851             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1852             gpgme_error = _GPGERR(gpgme_error);
  1853             gpg.gpgme_key_unref(key);
  1854             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1855             assert(gpgme_error != GPG_ERR_CONFLICT);
  1856         }
  1857             break;
  1858         case GPG_ERR_ENOMEM:
  1859             gpg.gpgme_op_keylist_end(session->ctx);
  1860             gpg.gpgme_release(import_ctx);
  1861             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1862             return PEP_OUT_OF_MEMORY;
  1863         default:
  1864             gpg.gpgme_op_keylist_end(session->ctx);
  1865             gpg.gpgme_release(import_ctx);
  1866             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1867             return PEP_UNKNOWN_ERROR;
  1868         };
  1869     } while (gpgme_error != GPG_ERR_EOF);
  1870 
  1871     gpg.gpgme_op_keylist_end(session->ctx);
  1872     gpg.gpgme_release(import_ctx);
  1873     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1874     return PEP_STATUS_OK;
  1875 }
  1876 
  1877 static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
  1878                             stringlist_t** keylist,
  1879                             int private_only) {
  1880     gpgme_error_t gpgme_error;
  1881     gpgme_key_t key;
  1882 
  1883     assert(session);
  1884     assert(keylist);
  1885 
  1886     *keylist = NULL;
  1887 
  1888     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
  1889     gpgme_error = _GPGERR(gpgme_error);
  1890     switch (gpgme_error) {
  1891         case GPG_ERR_NO_ERROR:
  1892             break;
  1893         case GPG_ERR_INV_VALUE:
  1894             assert(0);
  1895             return PEP_UNKNOWN_ERROR;
  1896         default:
  1897             gpg.gpgme_op_keylist_end(session->ctx);
  1898             return PEP_GET_KEY_FAILED;
  1899     };
  1900 
  1901     stringlist_t *_keylist = new_stringlist(NULL);
  1902     stringlist_t *_k = _keylist;
  1903 
  1904     do {
  1905         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1906         gpgme_error = _GPGERR(gpgme_error);
  1907         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1908         switch (gpgme_error) {
  1909             case GPG_ERR_EOF:
  1910                 break;
  1911             case GPG_ERR_NO_ERROR:
  1912                 assert(key);
  1913                 assert(key->subkeys);
  1914                 if(!key->subkeys)
  1915                     break;
  1916                 assert(key->uids);
  1917                 gpgme_user_id_t kuid = key->uids;
  1918                 // check that at least one uid's email matches pattern exactly,
  1919                 // modulo the email-diff heuristic
  1920                 while(kuid) {
  1921                     if((pattern == NULL) ||
  1922                        (strstr(pattern, "@") == NULL) || // not an email
  1923                        (kuid->email && _email_heuristic_match(kuid->email, pattern)))
  1924                     { 
  1925                         char *fpr = key->subkeys->fpr;
  1926                         assert(fpr);
  1927                         _k = stringlist_add(_k, fpr);
  1928                         assert(_k);
  1929                         if (_k == NULL){
  1930                             free_stringlist(_keylist);
  1931                             gpg.gpgme_op_keylist_end(session->ctx);
  1932                             return PEP_OUT_OF_MEMORY;
  1933                         }
  1934                         break;
  1935                     }
  1936                     kuid = kuid->next;
  1937                 }
  1938                 break;
  1939             case GPG_ERR_ENOMEM:
  1940                 free_stringlist(_keylist);
  1941                 gpg.gpgme_op_keylist_end(session->ctx);
  1942                 return PEP_OUT_OF_MEMORY;
  1943             default:
  1944                 gpg.gpgme_op_keylist_end(session->ctx);
  1945                 return PEP_UNKNOWN_ERROR;
  1946         };
  1947     } while (gpgme_error != GPG_ERR_EOF);
  1948 
  1949     gpg.gpgme_op_keylist_end(session->ctx);
  1950     if (_keylist->value == NULL) {
  1951         free_stringlist(_keylist);
  1952         _keylist = NULL;
  1953         
  1954         if (pattern != NULL) {
  1955             // If match failed, check to see if we've got a dotted address in the pattern.
  1956             // (last chance of the heuristic, really)
  1957             // If so, try again without any dots.
  1958             const char* dotpos = strstr(pattern, ".");
  1959             const char* atpos = strstr(pattern, "@");
  1960             if (dotpos && atpos && (dotpos < atpos)) {
  1961                 char* undotted = _undot_address(pattern);
  1962                 if (undotted) {
  1963                     PEP_STATUS status = _pgp_search_keys(session, undotted,
  1964                                                          keylist, private_only);
  1965                     free(undotted);
  1966                     return status;
  1967                 }
  1968             }
  1969         }
  1970     }    
  1971     
  1972     *keylist = _keylist;
  1973     return PEP_STATUS_OK;
  1974 }
  1975 
  1976 PEP_STATUS pgp_find_keys(
  1977     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1978     )
  1979 {
  1980     return _pgp_search_keys(session, pattern, keylist, 0);
  1981 }
  1982 
  1983 PEP_STATUS pgp_find_private_keys(
  1984     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1985 )
  1986 {
  1987     return _pgp_search_keys(session, pattern, keylist, 1);
  1988 }
  1989 
  1990 // this function is delivering a list of triples with fpr, email, name of all
  1991 // ultimatedly trusted private keys
  1992 
  1993 PEP_STATUS pgp_find_trusted_private_keys(
  1994         PEP_SESSION session, stringlist_t **keylist
  1995     )
  1996 {
  1997     assert(session && keylist);
  1998     if (!session || !keylist)
  1999         return PEP_ILLEGAL_VALUE;
  2000 
  2001     *keylist = NULL;
  2002 
  2003     gpgme_key_t key;
  2004     gpgme_error_t gpgme_error;
  2005 
  2006     stringlist_t *private_keylist = NULL;
  2007     PEP_STATUS status = pgp_find_private_keys(session, NULL, &private_keylist);
  2008     if (status)
  2009         return status;
  2010     if (!private_keylist || !private_keylist->value)
  2011         return status;
  2012 
  2013     stringlist_t *result_list = new_stringlist(NULL);
  2014     if (!result_list)
  2015         return PEP_OUT_OF_MEMORY;
  2016     stringlist_t *_result_list = result_list;
  2017 
  2018     stringlist_t *keylist_curr;
  2019     for (keylist_curr = private_keylist; keylist_curr && keylist_curr->value; keylist_curr = keylist_curr->next) {
  2020         // a. get key data
  2021         gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
  2022         gpgme_error = _GPGERR(gpgme_error);
  2023         assert(gpgme_error != GPG_ERR_ENOMEM);
  2024         switch (gpgme_error) {
  2025             case GPG_ERR_NO_ERROR:
  2026                 break;
  2027             case GPG_ERR_EOF:
  2028                 status = PEP_KEY_NOT_FOUND;
  2029                 break;
  2030             case GPG_ERR_INV_VALUE:
  2031                 status = PEP_ILLEGAL_VALUE;
  2032                 break;
  2033             case GPG_ERR_AMBIGUOUS_NAME:
  2034                 status = PEP_KEY_HAS_AMBIG_NAME;
  2035                 break;
  2036             case GPG_ERR_ENOMEM:
  2037                 free_stringlist(result_list);
  2038                 free_stringlist(private_keylist);
  2039                 return PEP_OUT_OF_MEMORY;
  2040             default:
  2041                 assert(0);
  2042                 status = PEP_UNKNOWN_ERROR;
  2043         }
  2044         if (key && gpgme_error == GPG_ERR_NO_ERROR) {
  2045             if (key->revoked || key->disabled) {
  2046                 status = PEP_KEY_UNSUITABLE;
  2047             }
  2048             else {
  2049                 if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
  2050                     if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
  2051                             key->uids && key->uids->email && key->uids->name) { 
  2052                         _result_list = stringlist_add(_result_list, key->fpr);
  2053                         if (!_result_list) {
  2054                             free_stringlist(result_list);
  2055                             free_stringlist(private_keylist);
  2056                             return PEP_OUT_OF_MEMORY;
  2057                         }
  2058                         _result_list = stringlist_add(_result_list, key->uids->email);
  2059                         if (!_result_list) {
  2060                             free_stringlist(result_list);
  2061                             free_stringlist(private_keylist);
  2062                             return PEP_OUT_OF_MEMORY;
  2063                         }
  2064                         _result_list = stringlist_add(_result_list, key->uids->name);
  2065                         if (!_result_list) {
  2066                             free_stringlist(result_list);
  2067                             free_stringlist(private_keylist);
  2068                             return PEP_OUT_OF_MEMORY;
  2069                         }
  2070                     }
  2071                 }
  2072             }
  2073         }
  2074     }
  2075 
  2076     free_stringlist(private_keylist);
  2077     *keylist = result_list;
  2078     return PEP_STATUS_OK;
  2079 }
  2080 
  2081 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  2082 {
  2083     gpgme_error_t gpgme_error;
  2084 
  2085     assert(session);
  2086     assert(pattern);
  2087 
  2088     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  2089         GPGME_EXPORT_MODE_EXTERN, NULL);
  2090     gpgme_error = _GPGERR(gpgme_error);
  2091     assert(gpgme_error != GPG_ERR_INV_VALUE);
  2092     if (gpgme_error == GPG_ERR_NO_ERROR)
  2093         return PEP_STATUS_OK;
  2094     else
  2095         return PEP_CANNOT_SEND_KEY;
  2096 }
  2097 
  2098 PEP_STATUS pgp_get_key_rating(
  2099     PEP_SESSION session,
  2100     const char *fpr,
  2101     PEP_comm_type *comm_type
  2102     )
  2103 {
  2104     PEP_STATUS status = PEP_STATUS_OK;
  2105     gpgme_error_t gpgme_error;
  2106     gpgme_key_t key;
  2107 
  2108     assert(session);
  2109     assert(fpr);
  2110     assert(comm_type);
  2111 
  2112     *comm_type = PEP_ct_unknown;
  2113 
  2114     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  2115     gpgme_error = _GPGERR(gpgme_error);
  2116     switch (gpgme_error) {
  2117     case GPG_ERR_NO_ERROR:
  2118         break;
  2119     case GPG_ERR_INV_VALUE:
  2120         assert(0);
  2121         return PEP_UNKNOWN_ERROR;
  2122     default:
  2123         return PEP_GET_KEY_FAILED;
  2124     };
  2125 
  2126     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  2127     gpgme_error = _GPGERR(gpgme_error);
  2128     assert(gpgme_error != GPG_ERR_INV_VALUE);
  2129 
  2130     if (key == NULL) {
  2131         gpg.gpgme_op_keylist_end(session->ctx);
  2132         return PEP_KEY_NOT_FOUND;
  2133     }
  2134 
  2135     switch (key->protocol) {
  2136     case GPGME_PROTOCOL_OpenPGP:
  2137     case GPGME_PROTOCOL_DEFAULT:
  2138         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  2139         break;
  2140     case GPGME_PROTOCOL_CMS:
  2141         *comm_type = PEP_ct_CMS_unconfirmed;
  2142         break;
  2143     default:
  2144         *comm_type = PEP_ct_unknown;
  2145         gpg.gpgme_op_keylist_end(session->ctx);
  2146         return PEP_STATUS_OK;
  2147     }
  2148     
  2149 
  2150     // N.B. and FIXME 
  2151     // We could get a key with a bad signing subkey and a good encryption
  2152     // subkey. For now, we reject this, because it forces large changes in
  2153     // how we rate keys. It's on the to-do list, but it's low priority.
  2154     // We don't really want to be doing much for tinkered keys in the first
  2155     // place.
  2156     switch (gpgme_error) {
  2157     case GPG_ERR_EOF:
  2158         break;
  2159     case GPG_ERR_NO_ERROR:
  2160         assert(key);
  2161         assert(key->subkeys);
  2162         
  2163         // is main key expired or revoked? If so, we can cut short this nonsense.
  2164         if (key->invalid)
  2165             *comm_type = PEP_ct_key_b0rken;
  2166         else if (key->revoked)
  2167             *comm_type = PEP_ct_key_revoked;            
  2168         else if (key->expired)
  2169             *comm_type = PEP_ct_key_expired;
  2170         else if (!key->subkeys)
  2171             *comm_type = PEP_ct_key_b0rken;
  2172         else {
  2173             // Ok, so we now need to check subkeys. Normally, we could just
  2174             // shortcut this by looking at key->can_sign and key->can_encrypt,
  2175             // but we want the REASON we can't use a key, so this gets ugly.
  2176             PEP_comm_type max_comm_type = *comm_type;
  2177 
  2178             // NOTE: 
  2179             // PEP_ct_pEp functions here as an unreachable top;
  2180             // it is impossible on just a key.
  2181             // IF THIS CHANGES, we must choose something else.
  2182             PEP_comm_type worst_sign = PEP_ct_pEp;
  2183             PEP_comm_type worst_enc = PEP_ct_pEp;
  2184 
  2185             PEP_comm_type error_sign = PEP_ct_unknown;
  2186             PEP_comm_type error_enc = PEP_ct_unknown;
  2187 
  2188             // We require that the underlying client NOT force-use expired or revoked
  2189             // subkeys instead of a valid one.
  2190             //
  2191             // So here we check all the subkeys; we make note of the existence
  2192             // of an expired, revoked, or invalid subkey, in case there is no
  2193             // other alternative (we want to return useful information).
  2194             // At the same time, we try to evaluate the least strong useable keys 
  2195             // for signing and encryption. If there is a useable one of both,
  2196             // the key comm_type corresponds to the lesser of these two least strong
  2197             // keys
  2198             for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  2199                 
  2200                 // Only evaluate signing keys or encryption keys
  2201                 if (sk->can_sign || sk->can_encrypt) {
  2202                     PEP_comm_type curr_sign = PEP_ct_no_encryption;
  2203                     PEP_comm_type curr_enc = PEP_ct_no_encryption;
  2204 
  2205 #ifdef GPGME_PK_ECC                    
  2206                     if ((sk->pubkey_algo != GPGME_PK_ECC && sk->length < 1024) 
  2207                         || (sk->pubkey_algo == GPGME_PK_ECC && sk->length < 160)) {
  2208 #else
  2209                     if (sk->length < 1024) {                        
  2210 #endif                        
  2211                         if (sk->can_sign)
  2212                             curr_sign = PEP_ct_key_too_short;
  2213                         if (sk->can_encrypt)                               
  2214                             curr_enc = PEP_ct_key_too_short;
  2215                     }
  2216                     else if 
  2217                         (
  2218                             (((sk->pubkey_algo == GPGME_PK_RSA)
  2219                                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  2220                                 || (sk->pubkey_algo == GPGME_PK_RSA_S))
  2221                                 && sk->length == 1024)
  2222 #ifdef GPGME_PK_ECC                    
  2223                             || (sk->pubkey_algo == GPGME_PK_ECC
  2224                                 && sk->length == 160)
  2225 #endif                             
  2226                         ) {
  2227                         if (sk->can_sign)
  2228                             curr_sign = PEP_ct_OpenPGP_weak_unconfirmed;
  2229                         if (sk->can_encrypt)                               
  2230                             curr_enc = PEP_ct_OpenPGP_weak_unconfirmed;
  2231                     }
  2232                     else {
  2233                         if (sk->can_sign)
  2234                             curr_sign = max_comm_type;
  2235                         if (sk->can_encrypt)
  2236                             curr_enc = max_comm_type;
  2237                     }
  2238                     if (sk->invalid) {
  2239                         if (sk->can_sign)
  2240                             curr_sign = PEP_ct_key_b0rken;
  2241                         if (sk->can_encrypt)                               
  2242                             curr_enc = PEP_ct_key_b0rken;
  2243                     }
  2244                     if (sk->expired) {
  2245                         if (sk->can_sign)
  2246                             curr_sign = PEP_ct_key_expired;
  2247                         if (sk->can_encrypt)                               
  2248                             curr_enc = PEP_ct_key_expired;
  2249                     }
  2250                     if (sk->revoked) {
  2251                         if (sk->can_sign)
  2252                             curr_sign = PEP_ct_key_revoked;
  2253                         if (sk->can_encrypt)                               
  2254                             curr_enc = PEP_ct_key_revoked;
  2255                     }
  2256                     switch (curr_sign) {
  2257                         case PEP_ct_key_b0rken:
  2258                         case PEP_ct_key_expired:
  2259                         case PEP_ct_key_revoked:
  2260                             error_sign = curr_sign;
  2261                             break;
  2262                         default:    
  2263                             if (sk->can_sign)
  2264                                 worst_sign = _MIN(curr_sign, worst_sign);
  2265                             break;
  2266                     }
  2267                     switch (curr_enc) {
  2268                         case PEP_ct_key_b0rken:
  2269                         case PEP_ct_key_expired:
  2270                         case PEP_ct_key_revoked:
  2271                             error_sign = curr_sign;
  2272                             break;
  2273                         default:    
  2274                             if (sk->can_encrypt)
  2275                                 worst_enc = _MIN(curr_enc, worst_enc);
  2276                             break;
  2277                     }                    
  2278                 }    
  2279             }
  2280             if (worst_enc == PEP_ct_pEp ||
  2281                 worst_sign == PEP_ct_pEp) {
  2282                 // No valid key was found for one or both; return a useful 
  2283                 // error comm_type
  2284                 PEP_comm_type error_ct = _MAX(error_enc, error_sign);    
  2285                 *comm_type = (error_ct == PEP_ct_unknown ? PEP_ct_key_b0rken : error_ct);
  2286             }
  2287             else {
  2288                 *comm_type = _MIN(max_comm_type, _MIN(worst_sign, worst_enc));
  2289             }                
  2290         }
  2291         break;
  2292     case GPG_ERR_ENOMEM:
  2293         gpg.gpgme_op_keylist_end(session->ctx);
  2294         *comm_type = PEP_ct_unknown;
  2295         return PEP_OUT_OF_MEMORY;
  2296     default:
  2297         gpg.gpgme_op_keylist_end(session->ctx);
  2298         return PEP_UNKNOWN_ERROR;
  2299     };
  2300 
  2301     gpg.gpgme_op_keylist_end(session->ctx);
  2302 
  2303     return status;
  2304 }
  2305 
  2306 
  2307 static ssize_t _nullwriter(
  2308         void *_handle,
  2309         const void *buffer,
  2310         size_t size
  2311     )
  2312 {
  2313     return size;
  2314 }
  2315 
  2316 typedef struct _replace_only_uid_state {
  2317     enum {
  2318         replace_uid_command = 0,
  2319         replace_uid_realname,
  2320         replace_uid_email,
  2321         replace_uid_comment,
  2322         replace_uid_adduid_ok,
  2323         replace_uid_select_for_delete,
  2324         replace_uid_delete,
  2325         replace_uid_delete_confirm,
  2326         replace_uid_select_for_trust,
  2327         replace_uid_trust,
  2328         replace_uid_trust_ultimate,
  2329         replace_uid_trust_ultimate_confirm,
  2330         replace_uid_quit,
  2331         replace_uid_save_okay,
  2332         replace_uid_exit,
  2333         replace_uid_error = -1
  2334     } state;
  2335 const char *realname;
  2336 const char *email;
  2337 } replace_only_uid_state;
  2338 
  2339 
  2340 static gpgme_error_t replace_only_uid_fsm(
  2341     void *_handle,
  2342     gpgme_status_code_t statuscode,
  2343     const char *args,
  2344     int fd
  2345 )
  2346 {
  2347     replace_only_uid_state *handle = _handle;
  2348         
  2349     switch (handle->state) {
  2350         case replace_uid_command:
  2351             if (statuscode == GPGME_STATUS_GET_LINE) {
  2352                 assert(strcmp(args, "keyedit.prompt") == 0);
  2353                 if (strcmp(args, "keyedit.prompt")) {
  2354                     handle->state = replace_uid_error;
  2355                     return GPG_ERR_GENERAL;
  2356                 }
  2357                 gpg.gpgme_io_write(fd, "adduid\n", 7);
  2358                 handle->state = replace_uid_realname;
  2359             }
  2360             break;
  2361             
  2362         case replace_uid_realname:
  2363             if (statuscode == GPGME_STATUS_GET_LINE) {
  2364                 assert(strcmp(args, "keygen.name") == 0);
  2365                 assert(handle->realname);
  2366                 if (strcmp(args, "keygen.name") || !handle->realname) {
  2367                     handle->state = replace_uid_error;
  2368                     return GPG_ERR_GENERAL;
  2369                 }
  2370                 size_t realname_strlen = strlen(handle->realname);
  2371                 char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
  2372                 if (!realname) {
  2373                     handle->state = replace_uid_error;
  2374                     return GPG_ERR_ENOMEM;
  2375                 }
  2376                 strlcpy(realname, handle->realname, realname_strlen + 1);
  2377                 realname[realname_strlen] = '\n';
  2378                 gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
  2379                 handle->state = replace_uid_email;
  2380                 free(realname);
  2381             }
  2382             break;
  2383             
  2384         case replace_uid_email:
  2385             if (statuscode == GPGME_STATUS_GET_LINE) {
  2386                 assert(strcmp(args, "keygen.email") == 0);
  2387                 assert(handle->email);
  2388                 if (strcmp(args, "keygen.email") || !handle->email) {
  2389                     handle->state = replace_uid_error;
  2390                     return GPG_ERR_GENERAL;
  2391                 }
  2392                 size_t email_strlen = strlen(handle->email);
  2393                 char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
  2394                 if (!email) {
  2395                     handle->state = replace_uid_error;
  2396                     return GPG_ERR_ENOMEM;
  2397                 }
  2398                 strlcpy(email, handle->email, email_strlen + 1);
  2399                 email[email_strlen] = '\n';
  2400                 gpg.gpgme_io_write(fd, email, email_strlen + 1);
  2401                 handle->state = replace_uid_comment;
  2402                 free(email);
  2403             }
  2404             break;
  2405 
  2406         case replace_uid_comment:
  2407             if (statuscode == GPGME_STATUS_GET_LINE) {
  2408                 assert(strcmp(args, "keygen.comment") == 0);
  2409                 if (strcmp(args, "keygen.comment") || !handle->email) {
  2410                     handle->state = replace_uid_error;
  2411                     return GPG_ERR_GENERAL;
  2412                 }
  2413                 gpg.gpgme_io_write(fd, "\n", 1);
  2414                 //handle->state = replace_uid_adduid_ok;
  2415                 handle->state = replace_uid_select_for_delete;
  2416             }
  2417             break;
  2418 /*
  2419         case replace_uid_adduid_ok:
  2420             if (statuscode == GPGME_STATUS_GET_LINE) {
  2421                 assert(strcmp(args, "keygen.userid.cmd") == 0);
  2422                 if (strcmp(args, "keygen.userid.cmd")) {
  2423                     handle->state = replace_uid_error;
  2424                     return GPG_ERR_GENERAL;
  2425                 }
  2426                 gpg.gpgme_io_write(fd, "O\n", 2);
  2427                 handle->state = replace_uid_select_for_delete;
  2428             }
  2429             break;
  2430 	    */
  2431 
  2432         case replace_uid_select_for_delete:
  2433             if (statuscode == GPGME_STATUS_GET_LINE) {
  2434                 assert(strcmp(args, "keyedit.prompt") == 0);
  2435                 if (strcmp(args, "keyedit.prompt")) {
  2436                     handle->state = replace_uid_error;
  2437                     return GPG_ERR_GENERAL;
  2438                 }
  2439                 gpg.gpgme_io_write(fd, "uid 1\n", 6);
  2440                 handle->state = replace_uid_delete;
  2441             }
  2442             break;
  2443 
  2444         case replace_uid_delete:
  2445             if (statuscode == GPGME_STATUS_GET_LINE) {
  2446                 assert(strcmp(args, "keyedit.prompt") == 0);
  2447                 if (strcmp(args, "keyedit.prompt")) {
  2448                     handle->state = replace_uid_error;
  2449                     return GPG_ERR_GENERAL;
  2450                 }
  2451                 gpg.gpgme_io_write(fd, "deluid\n", 7);
  2452                 handle->state = replace_uid_delete_confirm;
  2453             }
  2454             break;
  2455 
  2456         case replace_uid_delete_confirm:
  2457             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2458                 assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
  2459                 if (strcmp(args, "keyedit.remove.uid.okay")) {
  2460                     handle->state = replace_uid_error;
  2461                     return GPG_ERR_GENERAL;
  2462                 }
  2463                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2464                 handle->state = replace_uid_select_for_trust;
  2465             }
  2466             break;
  2467 
  2468         case replace_uid_select_for_trust:
  2469             if (statuscode == GPGME_STATUS_GET_LINE) {
  2470                 assert(strcmp(args, "keyedit.prompt") == 0);
  2471                 if (strcmp(args, "keyedit.prompt")) {
  2472                     handle->state = replace_uid_error;
  2473                     return GPG_ERR_GENERAL;
  2474                 }
  2475                 gpg.gpgme_io_write(fd, "uid 1\n", 6);
  2476                 handle->state = replace_uid_trust;
  2477             }
  2478             break;
  2479 
  2480         case replace_uid_trust:
  2481             if (statuscode == GPGME_STATUS_GET_LINE) {
  2482                 assert(strcmp(args, "keyedit.prompt") == 0);
  2483                 if (strcmp(args, "keyedit.prompt")) {
  2484                     handle->state = replace_uid_error;
  2485                     return GPG_ERR_GENERAL;
  2486                 }
  2487                 gpg.gpgme_io_write(fd, "trust\n", 6);
  2488                 handle->state = replace_uid_trust_ultimate;
  2489             }
  2490             break;
  2491 
  2492         case replace_uid_trust_ultimate:
  2493             if (statuscode == GPGME_STATUS_GET_LINE) {
  2494                 assert(strcmp(args, "edit_ownertrust.value") == 0);
  2495                 if (strcmp(args, "edit_ownertrust.value")) {
  2496                     handle->state = replace_uid_error;
  2497                     return GPG_ERR_GENERAL;
  2498                 }
  2499                 gpg.gpgme_io_write(fd, "5\n", 2);
  2500                 handle->state = replace_uid_trust_ultimate_confirm;
  2501             }
  2502             break;
  2503 
  2504         case replace_uid_trust_ultimate_confirm:
  2505             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2506                 assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
  2507                 if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
  2508                     handle->state = replace_uid_error;
  2509                     return GPG_ERR_GENERAL;
  2510                 }
  2511                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2512                 handle->state = replace_uid_quit;
  2513             }
  2514             break;
  2515 
  2516         case replace_uid_quit:
  2517             if (statuscode == GPGME_STATUS_GET_LINE) {
  2518                 assert(strcmp(args, "keyedit.prompt") == 0);
  2519                 if (strcmp(args, "keyedit.prompt")) {
  2520                     handle->state = replace_uid_error;
  2521                     return GPG_ERR_GENERAL;
  2522                 }
  2523                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2524                 handle->state = replace_uid_save_okay;
  2525             }
  2526             break;
  2527 
  2528         case replace_uid_save_okay:
  2529             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2530                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2531                 if (strcmp(args, "keyedit.save.okay")) {
  2532                     handle->state = replace_uid_error;
  2533                     return GPG_ERR_GENERAL;
  2534                 }
  2535                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2536                 handle->state = replace_uid_exit;
  2537             }
  2538             break;
  2539 
  2540         case replace_uid_exit:
  2541             break;
  2542 
  2543         case replace_uid_error:
  2544             return GPG_ERR_GENERAL;
  2545             
  2546         default:
  2547             break;
  2548     }
  2549     return GPG_ERR_NO_ERROR;
  2550 }
  2551 
  2552 PEP_STATUS pgp_replace_only_uid(
  2553         PEP_SESSION session,
  2554         const char* fpr,
  2555         const char* realname,
  2556         const char* email
  2557     )
  2558 {
  2559     PEP_STATUS status = PEP_STATUS_OK;
  2560     gpgme_error_t gpgme_error;
  2561     gpgme_key_t key;
  2562     gpgme_data_t output;
  2563     replace_only_uid_state handle;
  2564 
  2565     assert(session);
  2566     assert(fpr);
  2567     assert(realname);
  2568     assert(email);
  2569     
  2570     memset(&handle, 0, sizeof(replace_only_uid_state));
  2571     handle.realname = realname;
  2572     handle.email = email;
  2573 
  2574     status = find_single_key(session, fpr, &key);
  2575     if (status != PEP_STATUS_OK)
  2576         return status;
  2577 
  2578     struct gpgme_data_cbs data_cbs;
  2579     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2580     data_cbs.write = _nullwriter;
  2581     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2582 
  2583     gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, replace_only_uid_fsm, &handle,
  2584             output));
  2585     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2586     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2587         status = PEP_CANNOT_EDIT_KEY;
  2588     }
  2589 
  2590     gpg.gpgme_data_release(output);
  2591     gpg.gpgme_key_unref(key);
  2592 
  2593     return status;
  2594 }
  2595 
  2596 
  2597 typedef struct _renew_state {
  2598     enum {
  2599         renew_command = 0,
  2600         renew_date,
  2601         renew_secret_key,
  2602         renew_command2,
  2603         renew_date2,
  2604         renew_quit,
  2605         renew_save,
  2606         renew_exit,
  2607         renew_error = -1
  2608     } state;
  2609     const char *date_ref;
  2610 } renew_state;
  2611 
  2612 static gpgme_error_t renew_fsm(
  2613         void *_handle,
  2614         gpgme_status_code_t statuscode,
  2615         const char *args,
  2616         int fd
  2617     )
  2618 {
  2619     renew_state *handle = _handle;
  2620 
  2621     switch (handle->state) {
  2622         case renew_command:
  2623             if (statuscode == GPGME_STATUS_GET_LINE) {
  2624                 assert(strcmp(args, "keyedit.prompt") == 0);
  2625                 if (strcmp(args, "keyedit.prompt")) {
  2626                     handle->state = renew_error;
  2627                     return GPG_ERR_GENERAL;
  2628                 }
  2629                 gpg.gpgme_io_write(fd, "expire\n", 7);
  2630                 handle->state = renew_date;
  2631             }
  2632             break;
  2633 
  2634         case renew_date:
  2635             if (statuscode == GPGME_STATUS_GET_LINE) {
  2636                 assert(strcmp(args, "keygen.valid") == 0);
  2637                 if (strcmp(args, "keygen.valid")) {
  2638                     handle->state = renew_error;
  2639                     return GPG_ERR_GENERAL;
  2640                 }
  2641                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2642                 handle->state = renew_secret_key;
  2643             }
  2644             break;
  2645 
  2646         case renew_secret_key:
  2647             if (statuscode == GPGME_STATUS_GET_LINE) {
  2648                 assert(strcmp(args, "keyedit.prompt") == 0);
  2649                 if (strcmp(args, "keyedit.prompt")) {
  2650                     handle->state = renew_error;
  2651                     return GPG_ERR_GENERAL;
  2652                 }
  2653                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  2654                 handle->state = renew_command2;
  2655             }
  2656             break;
  2657 
  2658         case renew_command2:
  2659             if (statuscode == GPGME_STATUS_GET_LINE) {
  2660                 assert(strcmp(args, "keyedit.prompt") == 0);
  2661                 if (strcmp(args, "keyedit.prompt")) {
  2662                     handle->state = renew_error;
  2663                     return GPG_ERR_GENERAL;
  2664                 }
  2665                 gpg.gpgme_io_write(fd, "expire\n", 7);
  2666                 handle->state = renew_date2;
  2667             }
  2668             break;
  2669 
  2670         case renew_date2:
  2671             if (statuscode == GPGME_STATUS_GET_LINE) {
  2672                 assert(strcmp(args, "keygen.valid") == 0);
  2673                 if (strcmp(args, "keygen.valid")) {
  2674                     handle->state = renew_error;
  2675                     return GPG_ERR_GENERAL;
  2676                 }
  2677                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  2678                 handle->state = renew_quit;
  2679             }
  2680             break;
  2681 
  2682         case renew_quit:
  2683             if (statuscode == GPGME_STATUS_GET_LINE) {
  2684                 assert(strcmp(args, "keyedit.prompt") == 0);
  2685                 if (strcmp(args, "keyedit.prompt")) {
  2686                     handle->state = renew_error;
  2687                     return GPG_ERR_GENERAL;
  2688                 }
  2689                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2690                 handle->state = renew_save;
  2691             }
  2692             break;
  2693 
  2694         case renew_save:
  2695             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2696                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2697                 if (strcmp(args, "keyedit.save.okay")) {
  2698                     handle->state = renew_error;
  2699                     return GPG_ERR_GENERAL;
  2700                 }
  2701                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2702                 handle->state = renew_exit;
  2703             }
  2704             break;
  2705 
  2706         case renew_exit:
  2707             break;
  2708 
  2709         case renew_error:
  2710             return GPG_ERR_GENERAL;
  2711     }
  2712 
  2713     return GPG_ERR_NO_ERROR;
  2714 }
  2715 
  2716 
  2717 PEP_STATUS pgp_renew_key(
  2718         PEP_SESSION session,
  2719         const char *fpr,
  2720         const timestamp *ts
  2721     )
  2722 {
  2723     PEP_STATUS status = PEP_STATUS_OK;
  2724     gpgme_error_t gpgme_error;
  2725     gpgme_key_t key;
  2726     gpgme_data_t output;
  2727     renew_state handle;
  2728     char date_text[12];
  2729 
  2730     assert(session);
  2731     assert(fpr);
  2732 
  2733     memset(&handle, 0, sizeof(renew_state));
  2734     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  2735             ts->tm_mon + 1, ts->tm_mday);
  2736     handle.date_ref = date_text;
  2737 
  2738     status = find_single_key(session, fpr, &key);
  2739     if (status != PEP_STATUS_OK)
  2740         return status;
  2741 
  2742     struct gpgme_data_cbs data_cbs;
  2743     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2744     data_cbs.write = _nullwriter;
  2745     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2746 
  2747     gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  2748             output));
  2749     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2750     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2751         status = PEP_CANNOT_EDIT_KEY;
  2752     }
  2753 
  2754     gpg.gpgme_data_release(output);
  2755     gpg.gpgme_key_unref(key);
  2756 
  2757     return status;
  2758 }
  2759 
  2760 typedef struct _revoke_state {
  2761     enum {
  2762         revoke_command = 0,
  2763         revoke_approve,
  2764         revoke_reason_code,
  2765         revoke_reason_text,
  2766         revoke_reason_ok,
  2767         revoke_quit,
  2768         revoke_save,
  2769         revoke_exit,
  2770         revoke_error = -1
  2771     } state;
  2772     const char *reason_ref;
  2773 } revoke_state;
  2774 
  2775 
  2776 /*** unused?
  2777 static bool isemptystring(const char *str)
  2778 {
  2779     if (str == NULL)
  2780         return true;
  2781 
  2782     for (; str; str++) {
  2783         if (*str != ' ' && *str != '\t' && *str != '\n')
  2784             return false;
  2785     }
  2786 
  2787     return true;
  2788 }
  2789 ***/
  2790 
  2791 
  2792 static gpgme_error_t revoke_fsm(
  2793         void *_handle,
  2794         gpgme_status_code_t statuscode,
  2795         const char *args,
  2796         int fd
  2797     )
  2798 {
  2799     revoke_state *handle = _handle;
  2800 
  2801     switch (handle->state) {
  2802         case revoke_command:
  2803             if (statuscode == GPGME_STATUS_GET_LINE) {
  2804                 assert(strcmp(args, "keyedit.prompt") == 0);
  2805                 if (strcmp(args, "keyedit.prompt")) {
  2806                     handle->state = revoke_error;
  2807                     return GPG_ERR_GENERAL;
  2808                 }
  2809                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  2810                 handle->state = revoke_approve;
  2811             }
  2812             break;
  2813 
  2814         case revoke_approve:
  2815             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2816                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  2817                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  2818                     handle->state = revoke_error;
  2819                     return GPG_ERR_GENERAL;
  2820                 }
  2821                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2822                 handle->state = revoke_reason_code;
  2823             }
  2824             break;
  2825 
  2826         case revoke_reason_code:
  2827             if (statuscode == GPGME_STATUS_GET_LINE) {
  2828                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  2829                 if (strcmp(args, "ask_revocation_reason.code")) {
  2830                     handle->state = revoke_error;
  2831                     return GPG_ERR_GENERAL;
  2832                 }
  2833                 gpg.gpgme_io_write(fd, "1\n", 2);
  2834                 handle->state = revoke_reason_text;
  2835             }
  2836             break;
  2837 
  2838         case revoke_reason_text:
  2839             if (statuscode == GPGME_STATUS_GET_LINE) {
  2840                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  2841                 if (strcmp(args, "ask_revocation_reason.text")) {
  2842                     handle->state = revoke_error;
  2843                     return GPG_ERR_GENERAL;
  2844                 }
  2845                 // BUG: issues when reason given
  2846                 // Assertion failed: (gpg->cmd.code), function command_handler,
  2847                 // file engine-gpg.c, line 662.
  2848                 //
  2849                 // if (isemptystring(handle->reason_ref)) {
  2850                     gpg.gpgme_io_write(fd, "\n", 1);
  2851                 // }
  2852                 // else {
  2853                 //     size_t len = strlen(handle->reason_ref);
  2854                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  2855                 //     if (handle->reason_ref[len - 1] == '\n')
  2856                 //         gpg.gpgme_io_write(fd, "\n", 1);
  2857                 //     else
  2858                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  2859                 // }
  2860                 handle->state = revoke_reason_ok;
  2861             }
  2862             break;
  2863 
  2864         case revoke_reason_ok:
  2865             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2866                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  2867                 if (strcmp(args, "ask_revocation_reason.okay")) {
  2868                     handle->state = revoke_error;
  2869                     return GPG_ERR_GENERAL;
  2870                 }
  2871                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2872                 handle->state = revoke_quit;
  2873             }
  2874             break;
  2875 
  2876         case revoke_quit:
  2877             if (statuscode == GPGME_STATUS_GET_LINE) {
  2878                 assert(strcmp(args, "keyedit.prompt") == 0);
  2879                 if (strcmp(args, "keyedit.prompt")) {
  2880                     handle->state = revoke_error;
  2881                     return GPG_ERR_GENERAL;
  2882                 }
  2883                 gpg.gpgme_io_write(fd, "quit\n", 5);
  2884                 handle->state = revoke_save;
  2885             }
  2886             break;
  2887 
  2888         case revoke_save:
  2889             if (statuscode == GPGME_STATUS_GET_BOOL) {
  2890                 assert(strcmp(args, "keyedit.save.okay") == 0);
  2891                 if (strcmp(args, "keyedit.save.okay")) {
  2892                     handle->state = revoke_error;
  2893                     return GPG_ERR_GENERAL;
  2894                 }
  2895                 gpg.gpgme_io_write(fd, "Y\n", 2);
  2896                 handle->state = revoke_exit;
  2897             }
  2898             break;
  2899 
  2900         case revoke_exit:
  2901             break;
  2902 
  2903         case revoke_error:
  2904             return GPG_ERR_GENERAL;
  2905     }
  2906 
  2907     return GPG_ERR_NO_ERROR;
  2908 }
  2909 
  2910 PEP_STATUS pgp_revoke_key(
  2911         PEP_SESSION session,
  2912         const char *fpr,
  2913         const char *reason
  2914     )
  2915 {
  2916     PEP_STATUS status = PEP_STATUS_OK;
  2917     gpgme_error_t gpgme_error;
  2918     gpgme_key_t key;
  2919     gpgme_data_t output;
  2920     revoke_state handle;
  2921 
  2922     assert(session);
  2923     assert(fpr);
  2924 
  2925     memset(&handle, 0, sizeof(revoke_state));
  2926     handle.reason_ref = reason;
  2927 
  2928     status = find_single_key(session, fpr, &key);
  2929     if (status != PEP_STATUS_OK)
  2930         return status;
  2931 
  2932     struct gpgme_data_cbs data_cbs;
  2933     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2934     data_cbs.write = _nullwriter;
  2935     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2936 
  2937     gpgme_error = _GPGERR(gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  2938             output));
  2939     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2940     if(gpgme_error != GPG_ERR_NO_ERROR) {
  2941         status = PEP_CANNOT_EDIT_KEY;
  2942     }
  2943 
  2944     gpg.gpgme_data_release(output);
  2945     gpg.gpgme_key_unref(key);
  2946 
  2947     return status;
  2948 }
  2949 
  2950 PEP_STATUS pgp_key_expired(
  2951         PEP_SESSION session,
  2952         const char *fpr,
  2953         const time_t when,
  2954         bool *expired
  2955     )
  2956 {
  2957     PEP_STATUS status = PEP_STATUS_OK;
  2958     gpgme_key_t key;
  2959 
  2960     assert(session);
  2961     assert(fpr);
  2962     assert(expired);
  2963 
  2964     *expired = false;
  2965 
  2966     status = find_single_key(session, fpr, &key);
  2967     if (status != PEP_STATUS_OK)
  2968         return status;
  2969 
  2970     if ((key && key->expired) ||
  2971         (key && key->subkeys && key->subkeys->expired))
  2972     {
  2973         // Already marked expired
  2974         *expired = 1;
  2975     }
  2976     else if (key)
  2977     {
  2978         // Detect if will be expired
  2979         // i.e. Check that keys capabilities will
  2980         // not be expired at given time.
  2981         gpgme_subkey_t _sk;
  2982         bool crt_available = false;
  2983         bool sgn_available = false;
  2984         bool enc_available = false;
  2985         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  2986             if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
  2987                                                           // Also, zero means "does not expire"
  2988             {
  2989                 if (_sk->can_certify) crt_available = true;
  2990                 if (_sk->can_sign) sgn_available = true;
  2991                 if (_sk->can_encrypt) enc_available = true;
  2992                 // Authenticate is not used here.
  2993             }
  2994         }
  2995         if(!(crt_available && sgn_available && enc_available))
  2996         {
  2997             *expired = 1;
  2998         }
  2999     }
  3000     else
  3001     {
  3002         status = PEP_KEY_NOT_FOUND;
  3003     }
  3004 
  3005     gpg.gpgme_key_unref(key);
  3006     return status;
  3007 }
  3008 
  3009 PEP_STATUS pgp_key_revoked(
  3010         PEP_SESSION session,
  3011         const char *fpr,
  3012         bool *revoked
  3013     )
  3014 {
  3015     PEP_STATUS status = PEP_STATUS_OK;
  3016     gpgme_key_t key;
  3017 
  3018     assert(session);
  3019     assert(fpr);
  3020     assert(revoked);
  3021 
  3022     *revoked = false;
  3023 
  3024     status = find_single_key(session, fpr, &key);
  3025     if (status != PEP_STATUS_OK)
  3026         return status;
  3027 
  3028     if (key && key->subkeys)
  3029     {
  3030         *revoked = key->subkeys->revoked;
  3031     }
  3032     else
  3033     {
  3034         status = PEP_KEY_NOT_FOUND;
  3035     }
  3036 
  3037     gpg.gpgme_key_unref(key);
  3038     return status;
  3039 }
  3040 
  3041 PEP_STATUS pgp_key_created(
  3042         PEP_SESSION session,
  3043         const char *fpr,
  3044         time_t *created
  3045     )
  3046 {
  3047     PEP_STATUS status = PEP_STATUS_OK;
  3048     gpgme_key_t key;
  3049 
  3050     assert(session);
  3051     assert(fpr);
  3052     assert(created);
  3053 
  3054     *created = 0;
  3055 
  3056     status = find_single_key(session, fpr, &key);
  3057     if (status != PEP_STATUS_OK)
  3058         return status;
  3059 
  3060     if (key && key->subkeys)
  3061     {
  3062         *created = (time_t) key->subkeys->timestamp;
  3063     }
  3064     else
  3065     {
  3066         status = PEP_KEY_NOT_FOUND;
  3067     }
  3068 
  3069     gpg.gpgme_key_unref(key);
  3070     return status;
  3071 }
  3072 
  3073 PEP_STATUS pgp_binary(const char **path)
  3074 {
  3075     assert(path);
  3076     if (path == NULL)
  3077         return PEP_ILLEGAL_VALUE;
  3078 
  3079     *path = NULL;
  3080 
  3081     gpgme_engine_info_t info;
  3082     gpgme_error_t err = _GPGERR(gpg.gpgme_get_engine_info(&info));
  3083     assert(err == GPG_ERR_NO_ERROR);
  3084     if (err != GPG_ERR_NO_ERROR)
  3085         return PEP_OUT_OF_MEMORY;
  3086 
  3087     *path = info->file_name;
  3088 
  3089     return PEP_STATUS_OK;
  3090 }
  3091 
  3092 PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
  3093         bool *has_private) {
  3094     PEP_STATUS status = PEP_STATUS_OK;
  3095     gpgme_key_t output_key;
  3096     gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
  3097     *has_private = false;
  3098     switch (_GPGERR(gpgerr)) {
  3099         case GPG_ERR_EOF:
  3100         case GPG_ERR_INV_VALUE:
  3101             status = PEP_KEY_NOT_FOUND;
  3102             break;
  3103         case GPG_ERR_AMBIGUOUS_NAME:
  3104             status = PEP_KEY_HAS_AMBIG_NAME;
  3105             break;
  3106         case GPG_ERR_NO_ERROR:
  3107             *has_private = true;
  3108             gpg.gpgme_key_release(output_key);
  3109             break;
  3110         case GPG_ERR_ENOMEM:
  3111             status = PEP_OUT_OF_MEMORY;
  3112             break;
  3113         default:
  3114             status = PEP_UNKNOWN_ERROR;
  3115             break;
  3116     }
  3117     return status;
  3118 }
  3119 
  3120 PEP_STATUS pgp_config_cipher_suite(PEP_SESSION session,
  3121         PEP_CIPHER_SUITE suite)
  3122 {
  3123     // functionaliy unsupported; use gpg.conf
  3124 
  3125     switch (suite) {
  3126         case PEP_CIPHER_SUITE_DEFAULT:
  3127             return PEP_STATUS_OK;
  3128         default:
  3129             return PEP_CANNOT_CONFIG;
  3130     }
  3131 }
  3132