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