src/pgp_gpg.c
author Krista Grothoff <krista@pep-project.org>
Mon, 15 Aug 2016 13:37:11 +0200
branchENGINE-73
changeset 1010 24a4bc80878f
parent 1005 8e2c8253a385
child 1019 e38a6ec264bd
permissions -rw-r--r--
Stowing changes to work on another bug
     1 #include "platform.h"
     2 #include "pEp_internal.h"
     3 #include "pgp_gpg.h"
     4 
     5 #include <limits.h>
     6 
     7 #include "wrappers.h"
     8 
     9 #define _GPGERR(X) ((X) & 0xffffL)
    10 
    11 static void *gpgme;
    12 static struct gpg_s gpg;
    13 
    14 static bool ensure_config_values(stringlist_t *keys, stringlist_t *values, const char* config_file_path)
    15 {
    16     static char buf[MAX_LINELENGTH];
    17     int r;
    18     FILE *f;
    19     stringlist_t *_k;
    20     stringlist_t *_v;
    21     unsigned int i;
    22     unsigned int found = 0;
    23 
    24     f = Fopen(config_file_path, "r");
    25     if (f == NULL && errno == ENOMEM)
    26         return false;
    27 
    28     if (f != NULL) {
    29         int length = stringlist_length(keys);
    30         unsigned int n = (1 << length) - 1;
    31 
    32         // make sure we 1) have the same number of keys and values
    33         // and 2) we don't have more key/value pairs than
    34         // the size of the bitfield used to hold the indices
    35         // of key/value pairs matching keys in the config file.
    36         assert(length <= sizeof(unsigned int) * CHAR_BIT);
    37         assert(length == stringlist_length(values));
    38         if (!(length == stringlist_length(values) &&
    39               length <= sizeof(unsigned int) * CHAR_BIT)) {
    40             r = Fclose(f);
    41             assert(r == 0);
    42         
    43             return false;
    44         }
    45         
    46         do {
    47             char * s;
    48 
    49             s = Fgets(buf, MAX_LINELENGTH, f);
    50             if (!feof(f)) {
    51                 assert(s);
    52                 if (s == NULL)
    53                     return false;
    54 
    55                 if (s && !feof(f)) {
    56                     char * rest;
    57                     char * t = strtok_r(s, " ", &rest);
    58                     for (i = 1, _k = keys, _v = values; _k != NULL;
    59                             _k = _k->next, _v = _v->next, i <<= 1) {
    60                         if (t && strncmp(t, _k->value, strlen(_k->value)) == 0)
    61                             found |= i;
    62 
    63                         if (i == n) {
    64                             r = Fclose(f);
    65                             return true;
    66                         }
    67                     }
    68                 }
    69             }
    70         } while (!feof(f));
    71         f = Freopen(config_file_path, "a", f);
    72     }
    73     else {
    74         f = Fopen(config_file_path, "w");
    75     }
    76 
    77     assert(f);
    78     if (f == NULL)
    79         return false;
    80 
    81     for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
    82             _v = _v->next, i <<= 1) {
    83         if ((found & i) == 0) {
    84             r = Fprintf(f, "%s %s\n", _k->value, _v->value);
    85             assert(r >= 0);
    86         }
    87     }
    88 
    89     r = Fclose(f);
    90     assert(r == 0);
    91 
    92     return true;
    93 }
    94 
    95 
    96 PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
    97 {
    98     PEP_STATUS status = PEP_STATUS_OK;
    99     gpgme_error_t gpgme_error;
   100     bool bResult;
   101     
   102     if (in_first) {
   103         stringlist_t *conf_keys   = new_stringlist("keyserver");
   104         stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
   105 
   106         stringlist_add(conf_keys, "cert-digest-algo");
   107         stringlist_add(conf_values, "SHA256");
   108 
   109         stringlist_add(conf_keys, "no-emit-version");
   110         stringlist_add(conf_values, "");
   111 
   112         stringlist_add(conf_keys, "no-comments");
   113         stringlist_add(conf_values, "");
   114 
   115         stringlist_add(conf_keys, "personal-cipher-preferences");
   116         stringlist_add(conf_values, "AES AES256 AES192 CAST5");
   117 
   118         stringlist_add(conf_keys, "personal-digest-preferences");
   119         stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
   120 
   121         bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
   122 
   123         free_stringlist(conf_keys);
   124         free_stringlist(conf_values);
   125 
   126         assert(bResult);
   127         if(!bResult){
   128             status = PEP_INIT_NO_GPG_HOME;
   129             goto pep_error;
   130         }
   131 
   132         conf_keys = new_stringlist("default-cache-ttl");
   133         conf_values = new_stringlist("300");
   134 
   135         stringlist_add(conf_keys, "max-cache-ttl");
   136         stringlist_add(conf_values, "1200");
   137 
   138         bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf());
   139 
   140         free_stringlist(conf_keys);
   141         free_stringlist(conf_values);
   142 
   143         assert(bResult);
   144         if(!bResult){
   145             status = PEP_INIT_NO_GPG_HOME; /* FIXME: Wrong error here? */
   146             goto pep_error;
   147         }
   148 
   149         gpgme = dlopen(LIBGPGME, RTLD_LAZY);
   150         if (gpgme == NULL) {
   151             status = PEP_INIT_CANNOT_LOAD_GPGME;
   152             goto pep_error;
   153         }
   154 
   155         memset(&gpg, 0, sizeof(struct gpg_s));
   156 
   157         gpg.gpgme_set_locale
   158             = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
   159             "gpgme_set_locale");
   160         assert(gpg.gpgme_set_locale);
   161 
   162         gpg.gpgme_check
   163             = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
   164             "gpgme_check_version");
   165         assert(gpg.gpgme_check);
   166 
   167         gpg.gpgme_new
   168             = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
   169         assert(gpg.gpgme_new);
   170 
   171         gpg.gpgme_release
   172             = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
   173         assert(gpg.gpgme_release);
   174 
   175         gpg.gpgme_get_engine_info
   176             = (gpgme_get_engine_info_t) (intptr_t) dlsym(gpgme,
   177             "gpgme_get_engine_info");
   178         assert(gpg.gpgme_get_engine_info);
   179 
   180         gpg.gpgme_set_protocol
   181             = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
   182             "gpgme_set_protocol");
   183         assert(gpg.gpgme_set_protocol);
   184 
   185         gpg.gpgme_set_armor
   186             = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
   187             "gpgme_set_armor");
   188         assert(gpg.gpgme_set_armor);
   189 
   190         gpg.gpgme_data_new
   191             = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
   192             "gpgme_data_new");
   193         assert(gpg.gpgme_data_new);
   194 
   195         gpg.gpgme_data_new_from_mem
   196             = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
   197             "gpgme_data_new_from_mem");
   198         assert(gpg.gpgme_data_new_from_mem);
   199 
   200         gpg.gpgme_data_new_from_cbs
   201             = (gpgme_data_new_from_cbs_t) (intptr_t) dlsym(gpgme,
   202             "gpgme_data_new_from_cbs");
   203         assert(gpg.gpgme_data_new_from_cbs);
   204 
   205         gpg.gpgme_data_release
   206             = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
   207             "gpgme_data_release");
   208         assert(gpg.gpgme_data_release);
   209 
   210         gpg.gpgme_data_identify
   211             = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
   212             "gpgme_data_identify");
   213         assert(gpg.gpgme_data_identify);
   214 
   215         gpg.gpgme_data_seek
   216             = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
   217             "gpgme_data_seek");
   218         assert(gpg.gpgme_data_seek);
   219 
   220         gpg.gpgme_data_read
   221             = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
   222             "gpgme_data_read");
   223         assert(gpg.gpgme_data_read);
   224 
   225         gpg.gpgme_op_decrypt
   226             = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
   227             "gpgme_op_decrypt");
   228         assert(gpg.gpgme_op_decrypt);
   229 
   230         gpg.gpgme_op_verify
   231             = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
   232             "gpgme_op_verify");
   233         assert(gpg.gpgme_op_verify);
   234 
   235         gpg.gpgme_op_decrypt_verify
   236             = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
   237             "gpgme_op_decrypt_verify");
   238         assert(gpg.gpgme_op_decrypt_verify);
   239 
   240         gpg.gpgme_op_decrypt_result
   241             = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
   242             "gpgme_op_decrypt_result");
   243         assert(gpg.gpgme_op_decrypt_result);
   244 
   245         gpg.gpgme_op_encrypt_sign
   246             = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
   247             "gpgme_op_encrypt_sign");
   248         assert(gpg.gpgme_op_encrypt_sign);
   249 
   250         gpg.gpgme_op_verify_result
   251             = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
   252             "gpgme_op_verify_result");
   253         assert(gpg.gpgme_op_verify_result);
   254 
   255         gpg.gpgme_signers_clear
   256             = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
   257             "gpgme_signers_clear");
   258         assert(gpg.gpgme_signers_clear);
   259 
   260         gpg.gpgme_signers_add
   261             = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
   262             "gpgme_signers_add");
   263         assert(gpg.gpgme_signers_add);
   264 
   265         gpg.gpgme_get_key
   266             = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
   267         assert(gpg.gpgme_get_key);
   268 
   269         gpg.gpgme_op_genkey
   270             = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
   271             "gpgme_op_genkey");
   272         assert(gpg.gpgme_op_genkey);
   273 
   274         gpg.gpgme_op_genkey_result
   275             = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
   276             "gpgme_op_genkey_result");
   277         assert(gpg.gpgme_op_genkey_result);
   278 
   279         gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
   280             dlsym(gpgme, "gpgme_op_delete");
   281         assert(gpg.gpgme_op_delete);
   282 
   283         gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
   284             dlsym(gpgme, "gpgme_op_import");
   285         assert(gpg.gpgme_op_import);
   286 
   287         gpg.gpgme_op_import_result
   288             = (gpgme_op_import_result_t) (intptr_t) dlsym(gpgme,
   289             "gpgme_op_import_result");
   290         assert(gpg.gpgme_op_import_result);
   291 
   292         gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
   293             dlsym(gpgme, "gpgme_op_export");
   294         assert(gpg.gpgme_op_export);
   295 
   296         gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
   297             dlsym(gpgme, "gpgme_set_keylist_mode");
   298         assert(gpg.gpgme_set_keylist_mode);
   299 
   300         gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
   301             dlsym(gpgme, "gpgme_get_keylist_mode");
   302         assert(gpg.gpgme_get_keylist_mode);
   303 
   304         gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
   305             dlsym(gpgme, "gpgme_op_keylist_start");
   306         assert(gpg.gpgme_op_keylist_start);
   307 
   308         gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
   309             dlsym(gpgme, "gpgme_op_keylist_next");
   310         assert(gpg.gpgme_op_keylist_next);
   311 
   312         gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
   313             dlsym(gpgme, "gpgme_op_keylist_end");
   314         assert(gpg.gpgme_op_keylist_end);
   315 
   316         gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
   317             dlsym(gpgme, "gpgme_op_import_keys");
   318         assert(gpg.gpgme_op_import_keys);
   319 
   320         gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
   321             dlsym(gpgme, "gpgme_key_ref");
   322         assert(gpg.gpgme_key_ref);
   323 
   324         gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
   325             dlsym(gpgme, "gpgme_key_unref");
   326         assert(gpg.gpgme_key_unref);
   327 
   328         gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
   329             dlsym(gpgme, "gpgme_op_edit");
   330         assert(gpg.gpgme_op_edit);
   331 
   332         gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
   333             dlsym(gpgme, "gpgme_io_write");
   334         assert(gpg.gpgme_io_write);
   335 
   336         gpg.version = gpg.gpgme_check(NULL);
   337         
   338         const char * const cLocal = setlocale(LC_ALL, NULL);
   339         if (!cLocal || (strcmp(cLocal, "C") == 0))
   340             setlocale(LC_ALL, "");
   341 
   342         gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
   343 #ifdef LC_MESSAGES // Windoze
   344         gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
   345 #endif
   346     }
   347 
   348     gpgme_error = gpg.gpgme_new(&session->ctx);
   349     gpgme_error = _GPGERR(gpgme_error);
   350     if (gpgme_error != GPG_ERR_NO_ERROR) {
   351         status = PEP_INIT_GPGME_INIT_FAILED;
   352         goto pep_error;
   353     }
   354     assert(session->ctx);
   355 
   356     gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
   357     gpgme_error = _GPGERR(gpgme_error);
   358     assert(gpgme_error == GPG_ERR_NO_ERROR);
   359 
   360     gpg.gpgme_set_armor(session->ctx, 1);
   361 
   362     return PEP_STATUS_OK;
   363 
   364 pep_error:
   365     pgp_release(session, in_first);
   366     return status;
   367 }
   368 
   369 void pgp_release(PEP_SESSION session, bool out_last)
   370 {
   371     if (session->ctx) {
   372         gpg.gpgme_release(session->ctx);
   373         session->ctx = NULL;
   374     }
   375 
   376     if (out_last)
   377         if (gpgme)
   378             dlclose(gpgme);
   379 }
   380 
   381 PEP_STATUS pgp_decrypt_and_verify(
   382     PEP_SESSION session, const char *ctext, size_t csize,
   383     char **ptext, size_t *psize, stringlist_t **keylist
   384     )
   385 {
   386     PEP_STATUS result;
   387     gpgme_error_t gpgme_error;
   388     gpgme_data_t cipher, plain;
   389     gpgme_data_type_t dt;
   390 
   391     stringlist_t *_keylist = NULL;
   392     //int i_key = 0;
   393 
   394     assert(session);
   395     assert(ctext);
   396     assert(csize);
   397     assert(ptext);
   398     assert(psize);
   399     assert(keylist);
   400 
   401     *ptext = NULL;
   402     *psize = 0;
   403     *keylist = NULL;
   404 
   405     gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
   406     gpgme_error = _GPGERR(gpgme_error);
   407     assert(gpgme_error == GPG_ERR_NO_ERROR);
   408     if (gpgme_error != GPG_ERR_NO_ERROR) {
   409         if (gpgme_error == GPG_ERR_ENOMEM)
   410             return PEP_OUT_OF_MEMORY;
   411         else
   412             return PEP_UNKNOWN_ERROR;
   413     }
   414 
   415     gpgme_error = gpg.gpgme_data_new(&plain);
   416     gpgme_error = _GPGERR(gpgme_error);
   417     assert(gpgme_error == GPG_ERR_NO_ERROR);
   418     if (gpgme_error != GPG_ERR_NO_ERROR) {
   419         gpg.gpgme_data_release(cipher);
   420         if (gpgme_error == GPG_ERR_ENOMEM)
   421             return PEP_OUT_OF_MEMORY;
   422         else
   423             return PEP_UNKNOWN_ERROR;
   424     }
   425 
   426     dt = gpg.gpgme_data_identify(cipher);
   427     switch (dt) {
   428     case GPGME_DATA_TYPE_PGP_SIGNED:
   429     case GPGME_DATA_TYPE_PGP_OTHER:
   430         gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
   431             plain);
   432         gpgme_error = _GPGERR(gpgme_error);
   433         assert(gpgme_error != GPG_ERR_INV_VALUE);
   434         assert(gpgme_error != GPG_ERR_NO_DATA);
   435 
   436         switch (gpgme_error) {
   437             case GPG_ERR_NO_ERROR:
   438             {
   439                 gpgme_verify_result_t gpgme_verify_result;
   440                 char *_buffer = NULL;
   441                 size_t reading;
   442                 size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
   443                 gpgme_signature_t gpgme_signature;
   444 
   445                 assert(length != -1);
   446                 gpg.gpgme_data_seek(plain, 0, SEEK_SET);
   447 
   448                 // TODO: make things less memory consuming
   449                 // the following algorithm allocates memory for the complete
   450                 // text
   451 
   452                 _buffer = malloc(length + 1);
   453                 assert(_buffer);
   454                 if (_buffer == NULL) {
   455                     gpg.gpgme_data_release(plain);
   456                     gpg.gpgme_data_release(cipher);
   457                     return PEP_OUT_OF_MEMORY;
   458                 }
   459 
   460                 reading = gpg.gpgme_data_read(plain, _buffer, length);
   461                 assert(length == reading);
   462 
   463                 gpgme_verify_result =
   464                     gpg.gpgme_op_verify_result(session->ctx);
   465                 assert(gpgme_verify_result);
   466                 gpgme_signature = gpgme_verify_result->signatures;
   467 
   468                 if (gpgme_signature) {
   469                     stringlist_t *k;
   470                     _keylist = new_stringlist(NULL);
   471                     assert(_keylist);
   472                     if (_keylist == NULL) {
   473                         gpg.gpgme_data_release(plain);
   474                         gpg.gpgme_data_release(cipher);
   475                         free(_buffer);
   476                         return PEP_OUT_OF_MEMORY;
   477                     }
   478                     k = _keylist;
   479 
   480                     result = PEP_DECRYPTED_AND_VERIFIED;
   481                     do {
   482                         switch (_GPGERR(gpgme_signature->status)) {
   483                         case GPG_ERR_NO_ERROR:
   484                         {
   485                             // Some versions of gpg returns signer's 
   486                             // signing subkey fingerprint instead of
   487                             // signer's primary key fingerprint.
   488                             // This is meant to get signer's primary 
   489                             // key fingerprint, using subkey's.
   490 
   491                             gpgme_key_t key = NULL;
   492 
   493                             gpgme_error = gpg.gpgme_get_key(session->ctx,
   494                                 gpgme_signature->fpr, &key, 0);
   495                             gpgme_error = _GPGERR(gpgme_error);
   496                             assert(gpgme_error != GPG_ERR_ENOMEM);
   497                             if (gpgme_error == GPG_ERR_ENOMEM) {
   498                                 free_stringlist(_keylist);
   499                                 gpg.gpgme_data_release(plain);
   500                                 gpg.gpgme_data_release(cipher);
   501                                 free(_buffer);
   502                                 return PEP_OUT_OF_MEMORY;
   503                             }
   504                             // Primary key is given as the first subkey
   505                             if (gpgme_error == GPG_ERR_NO_ERROR &&  
   506                                 key && key->subkeys && key->subkeys->fpr 
   507                                 && key->subkeys->fpr[0])
   508                             {
   509                                 k = stringlist_add(k, key->subkeys->fpr);
   510 
   511                                 gpg.gpgme_key_unref(key);
   512 
   513                                 if (k == NULL) {
   514                                     free_stringlist(_keylist);
   515                                     gpg.gpgme_data_release(plain);
   516                                     gpg.gpgme_data_release(cipher);
   517                                     free(_buffer);
   518                                     return PEP_OUT_OF_MEMORY;
   519                                 }
   520                             }
   521                             else 
   522                             {
   523                                 result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   524                                 break;
   525                             }
   526                             break;
   527                         }
   528                         case GPG_ERR_CERT_REVOKED:
   529                         case GPG_ERR_BAD_SIGNATURE:
   530                             result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   531                             break;
   532                         case GPG_ERR_SIG_EXPIRED:
   533                         case GPG_ERR_KEY_EXPIRED:
   534                         case GPG_ERR_NO_PUBKEY:
   535                             k = stringlist_add(k, gpgme_signature->fpr);
   536                             if (k == NULL) {
   537                                 free_stringlist(_keylist);
   538                                 gpg.gpgme_data_release(plain);
   539                                 gpg.gpgme_data_release(cipher);
   540                                 free(_buffer);
   541                                 return PEP_OUT_OF_MEMORY;
   542                             }
   543                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   544                                 result = PEP_DECRYPTED;
   545                             break;
   546                         case GPG_ERR_GENERAL:
   547                             break;
   548                         default:
   549                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   550                                 result = PEP_DECRYPTED;
   551                             break;
   552                         }
   553                     } while ((gpgme_signature = gpgme_signature->next));
   554                 }
   555                 else {
   556                     result = PEP_DECRYPTED;
   557                 }
   558 
   559                 if (result == PEP_DECRYPTED_AND_VERIFIED
   560                     || result == PEP_DECRYPTED) {
   561                     *ptext = _buffer;
   562                     *psize = reading;
   563                     (*ptext)[*psize] = 0; // safeguard for naive users
   564                     *keylist = _keylist;
   565                 }
   566                 else {
   567                     free_stringlist(_keylist);
   568                     free(_buffer);
   569                 }
   570                 break;
   571             }
   572             case GPG_ERR_BAD_PASSPHRASE:
   573                 result = PEP_DECRYPT_NO_KEY;
   574                 break;
   575             case GPG_ERR_DECRYPT_FAILED:
   576             default:
   577             {
   578                 gpgme_decrypt_result_t gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   579                 result = PEP_DECRYPT_NO_KEY;
   580 
   581                 if (gpgme_decrypt_result != NULL) {
   582                     if (gpgme_decrypt_result->unsupported_algorithm)
   583                         *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   584                     else
   585                         *keylist = new_stringlist("");
   586                     assert(*keylist);
   587                     if (*keylist == NULL) {
   588                         result = PEP_OUT_OF_MEMORY;
   589                         break;
   590                     }
   591                     stringlist_t *_keylist = *keylist;
   592                     for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   593                         _keylist = stringlist_add(_keylist, r->keyid);
   594                         assert(_keylist);
   595                         if (_keylist == NULL) {
   596                             free_stringlist(*keylist);
   597                             *keylist = NULL;
   598                             result = PEP_OUT_OF_MEMORY;
   599                             break;
   600                         }
   601                     }
   602                     if (result == PEP_OUT_OF_MEMORY)
   603                         break;
   604                 }
   605             }
   606         }
   607         break;
   608 
   609     default:
   610         result = PEP_DECRYPT_WRONG_FORMAT;
   611     }
   612 
   613     gpg.gpgme_data_release(plain);
   614     gpg.gpgme_data_release(cipher);
   615     return result;
   616 }
   617 
   618 PEP_STATUS pgp_verify_text(
   619     PEP_SESSION session, const char *text, size_t size,
   620     const char *signature, size_t sig_size, stringlist_t **keylist
   621     )
   622 {
   623     PEP_STATUS result;
   624     gpgme_error_t gpgme_error;
   625     gpgme_data_t d_text, d_sig;
   626     stringlist_t *_keylist;
   627 
   628     assert(session);
   629     assert(text);
   630     assert(size);
   631     assert(signature);
   632     assert(sig_size);
   633     assert(keylist);
   634 
   635     *keylist = NULL;
   636 
   637     gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   638     gpgme_error = _GPGERR(gpgme_error);
   639     assert(gpgme_error == GPG_ERR_NO_ERROR);
   640     if (gpgme_error != GPG_ERR_NO_ERROR) {
   641         if (gpgme_error == GPG_ERR_ENOMEM)
   642             return PEP_OUT_OF_MEMORY;
   643         else
   644             return PEP_UNKNOWN_ERROR;
   645     }
   646 
   647     gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   648     gpgme_error = _GPGERR(gpgme_error);
   649     assert(gpgme_error == GPG_ERR_NO_ERROR);
   650     if (gpgme_error != GPG_ERR_NO_ERROR) {
   651         gpg.gpgme_data_release(d_text);
   652         if (gpgme_error == GPG_ERR_ENOMEM)
   653             return PEP_OUT_OF_MEMORY;
   654         else
   655             return PEP_UNKNOWN_ERROR;
   656     }
   657 
   658     gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
   659     gpgme_error = _GPGERR(gpgme_error);
   660     assert(gpgme_error != GPG_ERR_INV_VALUE);
   661 
   662     switch (gpgme_error) {
   663     case GPG_ERR_NO_ERROR:
   664     {
   665         gpgme_verify_result_t gpgme_verify_result;
   666         gpgme_signature_t gpgme_signature;
   667 
   668         gpgme_verify_result =
   669             gpg.gpgme_op_verify_result(session->ctx);
   670         assert(gpgme_verify_result);
   671         gpgme_signature = gpgme_verify_result->signatures;
   672 
   673         if (gpgme_signature) {
   674             stringlist_t *k;
   675             _keylist = new_stringlist(NULL);
   676             assert(_keylist);
   677             if (_keylist == NULL) {
   678                 gpg.gpgme_data_release(d_text);
   679                 gpg.gpgme_data_release(d_sig);
   680                 return PEP_OUT_OF_MEMORY;
   681             }
   682             k = _keylist;
   683 
   684             result = PEP_VERIFIED;
   685             do {
   686                 gpgme_key_t key;
   687                 memset(&key,0,sizeof(key));
   688 
   689                 // GPGME may give subkey's fpr instead of primary key's fpr. 
   690                 // Therefore we ask for the primary fingerprint instead
   691                 // we assume that gpgme_get_key can find key by subkey's fpr
   692                 gpgme_error = gpg.gpgme_get_key(session->ctx,
   693                     gpgme_signature->fpr, &key, 0);
   694                 gpgme_error = _GPGERR(gpgme_error);
   695                 assert(gpgme_error != GPG_ERR_ENOMEM);
   696                 if (gpgme_error == GPG_ERR_ENOMEM) {
   697                     free_stringlist(_keylist);
   698                     gpg.gpgme_data_release(d_text);
   699                     gpg.gpgme_data_release(d_sig);
   700                     return PEP_OUT_OF_MEMORY;
   701                 }
   702                 // Primary key is given as the first subkey
   703                 if (gpgme_error == GPG_ERR_NO_ERROR &&  
   704                     key && key->subkeys && key->subkeys->fpr 
   705                     && key->subkeys->fpr[0])
   706                 {
   707                     k = stringlist_add(k, key->subkeys->fpr);
   708 
   709                     gpg.gpgme_key_unref(key);
   710 
   711                     if (k == NULL) {
   712                         free_stringlist(_keylist);
   713                         gpg.gpgme_data_release(d_text);
   714                         gpg.gpgme_data_release(d_sig);
   715                         return PEP_OUT_OF_MEMORY;
   716                     }
   717                 }
   718                 else {
   719                     result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   720                     break;
   721                 }
   722 
   723                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   724                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   725                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   726                         if (result == PEP_VERIFIED
   727                             || result == PEP_VERIFIED_AND_TRUSTED)
   728                             result = PEP_UNENCRYPTED;
   729                     }
   730                     else {
   731                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   732                         break;
   733                     }
   734                 }
   735                 else {
   736                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   737                         if (result == PEP_VERIFIED)
   738                             result = PEP_VERIFIED_AND_TRUSTED;
   739                     }
   740                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   741                         // good
   742                     }
   743                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   744                         result = PEP_VERIFY_NO_KEY;
   745                     }
   746                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   747                         if (result == PEP_VERIFIED
   748                             || result == PEP_VERIFIED_AND_TRUSTED)
   749                             result = PEP_UNENCRYPTED;
   750                     }
   751                     else {
   752                         // do nothing
   753                     }
   754                 }
   755             } while ((gpgme_signature = gpgme_signature->next));
   756             *keylist = _keylist;
   757         }
   758         else {
   759             result = PEP_UNENCRYPTED;
   760         }
   761         break;
   762     }
   763         break;
   764     case GPG_ERR_NO_DATA:
   765         result = PEP_DECRYPT_WRONG_FORMAT;
   766         break;
   767     case GPG_ERR_INV_VALUE:
   768     default:
   769         result = PEP_UNKNOWN_ERROR;
   770         break;
   771     }
   772 
   773     gpg.gpgme_data_release(d_text);
   774     gpg.gpgme_data_release(d_sig);
   775 
   776     return result;
   777 }
   778 
   779 PEP_STATUS pgp_encrypt_and_sign(
   780     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   781     size_t psize, char **ctext, size_t *csize
   782     )
   783 {
   784     PEP_STATUS result;
   785     gpgme_error_t gpgme_error;
   786     gpgme_data_t plain, cipher;
   787     gpgme_key_t *rcpt;
   788     gpgme_encrypt_flags_t flags;
   789     const stringlist_t *_keylist;
   790     int i, j;
   791 
   792     assert(session);
   793     assert(keylist);
   794     assert(ptext);
   795     assert(psize);
   796     assert(ctext);
   797     assert(csize);
   798 
   799     *ctext = NULL;
   800     *csize = 0;
   801 
   802     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
   803     gpgme_error = _GPGERR(gpgme_error);
   804     assert(gpgme_error == GPG_ERR_NO_ERROR);
   805     if (gpgme_error != GPG_ERR_NO_ERROR) {
   806         if (gpgme_error == GPG_ERR_ENOMEM)
   807             return PEP_OUT_OF_MEMORY;
   808         else
   809             return PEP_UNKNOWN_ERROR;
   810     }
   811 
   812     gpgme_error = gpg.gpgme_data_new(&cipher);
   813     gpgme_error = _GPGERR(gpgme_error);
   814     assert(gpgme_error == GPG_ERR_NO_ERROR);
   815     if (gpgme_error != GPG_ERR_NO_ERROR) {
   816         gpg.gpgme_data_release(plain);
   817         if (gpgme_error == GPG_ERR_ENOMEM)
   818             return PEP_OUT_OF_MEMORY;
   819         else
   820             return PEP_UNKNOWN_ERROR;
   821     }
   822 
   823     rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
   824     assert(rcpt);
   825     if (rcpt == NULL) {
   826         gpg.gpgme_data_release(plain);
   827         gpg.gpgme_data_release(cipher);
   828         return PEP_OUT_OF_MEMORY;
   829     }
   830 
   831     gpg.gpgme_signers_clear(session->ctx);
   832 
   833     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
   834         assert(_keylist->value);
   835         gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
   836             &rcpt[i], 0);
   837         gpgme_error = _GPGERR(gpgme_error);
   838         assert(gpgme_error != GPG_ERR_ENOMEM);
   839 
   840         switch (gpgme_error) {
   841         case GPG_ERR_ENOMEM:
   842             for (j = 0; j<i; j++)
   843                 gpg.gpgme_key_unref(rcpt[j]);
   844             free(rcpt);
   845             gpg.gpgme_data_release(plain);
   846             gpg.gpgme_data_release(cipher);
   847             return PEP_OUT_OF_MEMORY;
   848         case GPG_ERR_NO_ERROR:
   849             if (i == 0) {
   850                 gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
   851                 _gpgme_error = _GPGERR(_gpgme_error);
   852                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
   853             }
   854             break;
   855         case GPG_ERR_EOF:
   856             for (j = 0; j<i; j++)
   857                 gpg.gpgme_key_unref(rcpt[j]);
   858             free(rcpt);
   859             gpg.gpgme_data_release(plain);
   860             gpg.gpgme_data_release(cipher);
   861             return PEP_KEY_NOT_FOUND;
   862         case GPG_ERR_AMBIGUOUS_NAME:
   863             for (j = 0; j<i; j++)
   864                 gpg.gpgme_key_unref(rcpt[j]);
   865             free(rcpt);
   866             gpg.gpgme_data_release(plain);
   867             gpg.gpgme_data_release(cipher);
   868             return PEP_KEY_HAS_AMBIG_NAME;
   869         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
   870             // FPR is not a fingerprint or key ID
   871             for (j = 0; j<i; j++)
   872                 gpg.gpgme_key_unref(rcpt[j]);
   873             free(rcpt);
   874             gpg.gpgme_data_release(plain);
   875             gpg.gpgme_data_release(cipher);
   876             return PEP_GET_KEY_FAILED;
   877         }
   878     }
   879 
   880     // TODO: remove that and replace with proper key management
   881     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
   882 
   883     gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
   884         plain, cipher);
   885     gpgme_error = _GPGERR(gpgme_error);
   886     switch (gpgme_error) {
   887     case GPG_ERR_NO_ERROR:
   888     {
   889         char *_buffer = NULL;
   890         size_t reading;
   891         size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
   892         assert(length != -1);
   893         gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
   894 
   895         // TODO: make things less memory consuming
   896         // the following algorithm allocates a buffer for the complete text
   897 
   898         _buffer = malloc(length + 1);
   899         assert(_buffer);
   900         if (_buffer == NULL) {
   901             for (j = 0; j<stringlist_length(keylist); j++)
   902                 gpg.gpgme_key_unref(rcpt[j]);
   903             free(rcpt);
   904             gpg.gpgme_data_release(plain);
   905             gpg.gpgme_data_release(cipher);
   906             return PEP_OUT_OF_MEMORY;
   907         }
   908 
   909         reading = gpg.gpgme_data_read(cipher, _buffer, length);
   910         assert(length == reading);
   911 
   912         *ctext = _buffer;
   913         *csize = reading;
   914         (*ctext)[*csize] = 0; // safeguard for naive users
   915         result = PEP_STATUS_OK;
   916         break;
   917     }
   918     default:
   919         result = PEP_UNKNOWN_ERROR;
   920     }
   921 
   922     for (j = 0; j<stringlist_length(keylist); j++)
   923         gpg.gpgme_key_unref(rcpt[j]);
   924     free(rcpt);
   925     gpg.gpgme_data_release(plain);
   926     gpg.gpgme_data_release(cipher);
   927     return result;
   928 }
   929 
   930 PEP_STATUS pgp_generate_keypair(
   931     PEP_SESSION session, pEp_identity *identity
   932     )
   933 {
   934     gpgme_error_t gpgme_error;
   935     char *parms;
   936     const char *template =
   937         "<GnupgKeyParms format=\"internal\">\n"
   938         "Key-Type: RSA\n"
   939         "Key-Length: 4096\n"
   940         "Subkey-Type: RSA\n"
   941         "Subkey-Length: 4096\n"
   942         "Name-Real: %s\n"
   943         "Name-Email: %s\n"
   944         /* "Passphrase: %s\n" */
   945         "Expire-Date: 1y\n"
   946         "</GnupgKeyParms>\n";
   947     int result;
   948     gpgme_genkey_result_t gpgme_genkey_result;
   949 
   950     assert(session);
   951     assert(identity);
   952     assert(identity->address);
   953     assert(identity->fpr == NULL || identity->fpr[0] == 0);
   954     assert(identity->username);
   955 
   956     parms = calloc(1, PARMS_MAX);
   957     assert(parms);
   958     if (parms == NULL)
   959         return PEP_OUT_OF_MEMORY;
   960 
   961     result = snprintf(parms, PARMS_MAX, template, identity->username,
   962         identity->address); // , session->passphrase);
   963     assert(result < PARMS_MAX);
   964     if (result >= PARMS_MAX) {
   965         free(parms);
   966         return PEP_BUFFER_TOO_SMALL;
   967     }
   968 
   969     gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
   970     gpgme_error = _GPGERR(gpgme_error);
   971     free(parms);
   972 
   973     switch (gpgme_error) {
   974     case GPG_ERR_NO_ERROR:
   975         break;
   976     case GPG_ERR_INV_VALUE:
   977         return PEP_ILLEGAL_VALUE;
   978     case GPG_ERR_GENERAL:
   979         return PEP_CANNOT_CREATE_KEY;
   980     default:
   981         assert(0);
   982         return PEP_UNKNOWN_ERROR;
   983     }
   984 
   985     gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
   986     assert(gpgme_genkey_result);
   987     assert(gpgme_genkey_result->fpr);
   988 
   989     free(identity->fpr);
   990     identity->fpr = strdup(gpgme_genkey_result->fpr);
   991     if (identity->fpr == NULL)
   992         return PEP_OUT_OF_MEMORY;
   993 
   994     return PEP_STATUS_OK;
   995 }
   996 
   997 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
   998 {
   999     gpgme_error_t gpgme_error;
  1000     gpgme_key_t key;
  1001 
  1002     assert(session);
  1003     assert(fpr);
  1004 
  1005     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1006     gpgme_error = _GPGERR(gpgme_error);
  1007     assert(gpgme_error != GPG_ERR_ENOMEM);
  1008     switch (gpgme_error) {
  1009     case GPG_ERR_NO_ERROR:
  1010         break;
  1011     case GPG_ERR_EOF:
  1012         return PEP_KEY_NOT_FOUND;
  1013     case GPG_ERR_INV_VALUE:
  1014         return PEP_ILLEGAL_VALUE;
  1015     case GPG_ERR_AMBIGUOUS_NAME:
  1016         return PEP_KEY_HAS_AMBIG_NAME;
  1017     case GPG_ERR_ENOMEM:
  1018         return PEP_OUT_OF_MEMORY;
  1019     default:
  1020         assert(0);
  1021         return PEP_UNKNOWN_ERROR;
  1022     }
  1023 
  1024     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1025     gpgme_error = _GPGERR(gpgme_error);
  1026     gpg.gpgme_key_unref(key);
  1027     switch (gpgme_error) {
  1028     case GPG_ERR_NO_ERROR:
  1029         break;
  1030     case GPG_ERR_INV_VALUE:
  1031         assert(0);
  1032         return PEP_UNKNOWN_ERROR;
  1033     case GPG_ERR_NO_PUBKEY:
  1034         assert(0);
  1035         return PEP_KEY_NOT_FOUND;
  1036     case GPG_ERR_AMBIGUOUS_NAME:
  1037         assert(0);
  1038         return PEP_KEY_HAS_AMBIG_NAME;
  1039     default:
  1040         assert(0);
  1041         return PEP_UNKNOWN_ERROR;
  1042     }
  1043 
  1044     return PEP_STATUS_OK;
  1045 }
  1046 
  1047 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1048                               size_t size, identity_list **private_idents)
  1049 {
  1050     gpgme_error_t gpgme_error;
  1051     gpgme_data_t dh;
  1052 
  1053     assert(session);
  1054     assert(key_data);
  1055    
  1056     if(private_idents) 
  1057         *private_idents = NULL;
  1058 
  1059     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1060     gpgme_error = _GPGERR(gpgme_error);
  1061     assert(gpgme_error != GPG_ERR_ENOMEM);
  1062     switch (gpgme_error) {
  1063     case GPG_ERR_NO_ERROR:
  1064         break;
  1065     case GPG_ERR_ENOMEM:
  1066         return PEP_OUT_OF_MEMORY;
  1067     case GPG_ERR_INV_VALUE:
  1068         assert(0);
  1069         return PEP_UNKNOWN_ERROR;
  1070     default:
  1071         assert(0);
  1072         return PEP_UNKNOWN_ERROR;
  1073     }
  1074 
  1075     gpgme_import_result_t gpgme_import_result;
  1076 
  1077     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1078     gpgme_error = _GPGERR(gpgme_error);
  1079     switch (gpgme_error) {
  1080     case GPG_ERR_NO_ERROR:
  1081         if(private_idents) 
  1082         {
  1083             gpgme_import_result =
  1084                 gpg.gpgme_op_import_result(session->ctx);
  1085             assert(gpgme_import_result);
  1086             gpgme_import_status_t import;
  1087             for (import = gpgme_import_result->imports; 
  1088                  import; 
  1089                  import = import->next)
  1090              {
  1091                 if (import &&
  1092                     import->result == GPG_ERR_NO_ERROR &&
  1093                     import->status & GPGME_IMPORT_SECRET )
  1094                 {
  1095                     gpgme_key_t key = NULL;
  1096 
  1097                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1098                         import->fpr, &key, 0);
  1099                     gpgme_error = _GPGERR(gpgme_error);
  1100                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1101                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1102                         gpg.gpgme_data_release(dh);
  1103                         return PEP_OUT_OF_MEMORY;
  1104                     }
  1105                     
  1106                     if (gpgme_error == GPG_ERR_NO_ERROR &&  
  1107                         key && key->uids && 
  1108                         key->uids->email && key->uids->name)
  1109                     {
  1110                         pEp_identity *ident = new_identity(
  1111                              key->uids->email, import->fpr, NULL, key->uids->name);
  1112 
  1113                         gpg.gpgme_key_unref(key);
  1114 
  1115                         if (ident == NULL) {
  1116                             gpg.gpgme_data_release(dh);
  1117                             return PEP_OUT_OF_MEMORY;
  1118                         }
  1119 
  1120                         *private_idents = identity_list_add(*private_idents, ident);
  1121 
  1122                         if (*private_idents == NULL) {
  1123                             gpg.gpgme_data_release(dh);
  1124                             return PEP_OUT_OF_MEMORY;
  1125                         }
  1126                     }
  1127                     else 
  1128                     {
  1129                         gpg.gpgme_key_unref(key);
  1130                         gpg.gpgme_data_release(dh);
  1131                         return PEP_UNKNOWN_ERROR;
  1132                     }
  1133                 }
  1134             }
  1135         }
  1136         break;
  1137     case GPG_ERR_INV_VALUE:
  1138         assert(0);
  1139         gpg.gpgme_data_release(dh);
  1140         return PEP_UNKNOWN_ERROR;
  1141     case GPG_ERR_NO_DATA:
  1142         gpg.gpgme_data_release(dh);
  1143         return PEP_ILLEGAL_VALUE;
  1144     default:
  1145         assert(0);
  1146         gpg.gpgme_data_release(dh);
  1147         return PEP_UNKNOWN_ERROR;
  1148     }
  1149 
  1150     gpg.gpgme_data_release(dh);
  1151     return PEP_STATUS_OK;
  1152 }
  1153 
  1154 PEP_STATUS pgp_export_keydata(
  1155     PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1156     )
  1157 {
  1158     gpgme_error_t gpgme_error;
  1159     gpgme_data_t dh;
  1160     size_t _size;
  1161     char *buffer;
  1162     int reading;
  1163 
  1164     assert(session);
  1165     assert(fpr);
  1166     assert(key_data);
  1167     assert(size);
  1168 
  1169     gpgme_error = gpg.gpgme_data_new(&dh);
  1170     gpgme_error = _GPGERR(gpgme_error);
  1171     assert(gpgme_error != GPG_ERR_ENOMEM);
  1172     switch (gpgme_error) {
  1173     case GPG_ERR_NO_ERROR:
  1174         break;
  1175     case GPG_ERR_ENOMEM:
  1176         return PEP_OUT_OF_MEMORY;
  1177     case GPG_ERR_INV_VALUE:
  1178         assert(0);
  1179         return PEP_UNKNOWN_ERROR;
  1180     default:
  1181         assert(0);
  1182         return PEP_UNKNOWN_ERROR;
  1183     }
  1184 
  1185     gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1186         GPGME_EXPORT_MODE_MINIMAL, dh);
  1187     gpgme_error = _GPGERR(gpgme_error);
  1188     switch (gpgme_error) {
  1189     case GPG_ERR_NO_ERROR:
  1190         break;
  1191     case GPG_ERR_EOF:
  1192         gpg.gpgme_data_release(dh);
  1193         return PEP_KEY_NOT_FOUND;
  1194     case GPG_ERR_INV_VALUE:
  1195         assert(0);
  1196         gpg.gpgme_data_release(dh);
  1197         return PEP_UNKNOWN_ERROR;
  1198     default:
  1199         assert(0);
  1200         gpg.gpgme_data_release(dh);
  1201         return PEP_UNKNOWN_ERROR;
  1202     };
  1203 
  1204     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1205     assert(_size != -1);
  1206     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1207 
  1208     buffer = malloc(_size + 1);
  1209     assert(buffer);
  1210     if (buffer == NULL) {
  1211         gpg.gpgme_data_release(dh);
  1212         return PEP_OUT_OF_MEMORY;
  1213     }
  1214 
  1215     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1216     assert(_size == reading);
  1217 
  1218     // safeguard for the naive user
  1219     buffer[_size] = 0;
  1220 
  1221     *key_data = buffer;
  1222     *size = _size;
  1223 
  1224     gpg.gpgme_data_release(dh);
  1225     return PEP_STATUS_OK;
  1226 }
  1227 
  1228 PEP_STATUS pgp_list_keys(PEP_SESSION session, stringpair_list_t** key_email_list) {
  1229     gpgme_error_t gpgme_error;
  1230     assert(session);
  1231     assert(key_email_list);
  1232     
  1233     if (!session || !key_email_list)
  1234         return PEP_ILLEGAL_VALUE;
  1235     
  1236     *key_email_list = NULL;
  1237     
  1238     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, NULL, 0);
  1239     gpgme_error = _GPGERR(gpgme_error);
  1240     
  1241     switch(gpgme_error) {
  1242         case GPG_ERR_NO_ERROR:
  1243             break;
  1244         case GPG_ERR_INV_VALUE:
  1245             assert(0);
  1246             return PEP_UNKNOWN_ERROR;
  1247         default:
  1248             gpg.gpgme_op_keylist_end(session->ctx);
  1249             return PEP_GET_KEY_FAILED;        
  1250     };
  1251     
  1252     gpgme_key_t key;
  1253     stringpair_list_t* _key_email_list = new_stringpair_list(NULL);
  1254     stringpair_list_t* list_curr = _key_email_list;
  1255     stringpair_t* key_email_pair = NULL;
  1256     
  1257     do {
  1258         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1259         gpgme_error = _GPGERR(gpgme_error);
  1260       
  1261         switch(gpgme_error) {
  1262             case GPG_ERR_EOF:
  1263                 break;
  1264             case GPG_ERR_NO_ERROR:
  1265                 assert(key);
  1266                 assert(key->subkeys);
  1267                 if (!key || !key->subkeys)
  1268                     return PEP_GET_KEY_FAILED;
  1269                
  1270                 // first subkey is primary key
  1271                 char* fpr = key->subkeys->fpr;
  1272                 char* primary_email = key->uids->email;
  1273                 assert(fpr);
  1274                 assert(primary_email);
  1275                 if (!fpr || !primary_email)
  1276                     return PEP_GET_KEY_FAILED;
  1277                 
  1278                 key_email_pair = new_stringpair(fpr, primary_email);
  1279                 assert(key_email_pair);
  1280                 
  1281                 if (key_email_pair) {
  1282                     list_curr = stringpair_list_add(list_curr, key_email_pair);
  1283                     key_email_pair = NULL;
  1284                     
  1285                     assert(list_curr);
  1286                     if (list_curr != NULL)
  1287                         break;
  1288                     else
  1289                         free_stringpair(key_email_pair);
  1290                 }
  1291                 // else fallthrough (list_curr or key_email_pair wasn't allocateable)
  1292             case GPG_ERR_ENOMEM:
  1293                 free_stringpair_list(_key_email_list);
  1294                 gpg.gpgme_op_keylist_end(session->ctx);
  1295                 return PEP_OUT_OF_MEMORY;
  1296             default:
  1297                 gpg.gpgme_op_keylist_end(session->ctx);
  1298                 return PEP_UNKNOWN_ERROR;
  1299         }
  1300     } while (gpgme_error != GPG_ERR_EOF);
  1301     
  1302     if (_key_email_list->value == NULL) {
  1303         free_stringpair_list(_key_email_list);
  1304         _key_email_list = NULL;
  1305     }
  1306     
  1307     *key_email_list = _key_email_list;
  1308     
  1309     return PEP_STATUS_OK;
  1310 }
  1311 
  1312 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1313     gpgme_keylist_mode_t add_mode)
  1314 {
  1315     gpgme_error_t gpgme_error;
  1316     gpgme_keylist_mode_t mode;
  1317 
  1318     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1319 
  1320     mode &= ~remove_mode;
  1321     mode |= add_mode;
  1322 
  1323     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1324     gpgme_error = _GPGERR(gpgme_error);
  1325     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1326 }
  1327 
  1328 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1329 {
  1330     gpgme_error_t gpgme_error;
  1331     gpgme_key_t key;
  1332 
  1333     assert(session);
  1334     assert(pattern);
  1335 
  1336     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1337 
  1338     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1339     gpgme_error = _GPGERR(gpgme_error);
  1340     switch (gpgme_error) {
  1341     case GPG_ERR_NO_ERROR:
  1342         break;
  1343     case GPG_ERR_INV_VALUE:
  1344         assert(0);
  1345         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1346         return PEP_UNKNOWN_ERROR;
  1347     default:
  1348         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1349         return PEP_GET_KEY_FAILED;
  1350     };
  1351 
  1352     gpgme_ctx_t import_ctx;
  1353     gpgme_error = gpg.gpgme_new(&import_ctx);
  1354     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1355 
  1356     do {
  1357         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1358         gpgme_error = _GPGERR(gpgme_error);
  1359         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1360         switch (gpgme_error) {
  1361         case GPG_ERR_EOF:
  1362             break;
  1363         case GPG_ERR_NO_ERROR:
  1364         {
  1365             gpgme_error_t gpgme_error;
  1366             gpgme_key_t keys[2];
  1367 
  1368             keys[0] = key;
  1369             keys[1] = NULL;
  1370 
  1371             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1372             gpgme_error = _GPGERR(gpgme_error);
  1373             gpg.gpgme_key_unref(key);
  1374             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1375             assert(gpgme_error != GPG_ERR_CONFLICT);
  1376         }
  1377             break;
  1378         case GPG_ERR_ENOMEM:
  1379             gpg.gpgme_op_keylist_end(session->ctx);
  1380             gpg.gpgme_release(import_ctx);
  1381             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1382             return PEP_OUT_OF_MEMORY;
  1383         default:
  1384             gpg.gpgme_op_keylist_end(session->ctx);
  1385             gpg.gpgme_release(import_ctx);
  1386             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1387             return PEP_UNKNOWN_ERROR;
  1388         };
  1389     } while (gpgme_error != GPG_ERR_EOF);
  1390 
  1391     gpg.gpgme_op_keylist_end(session->ctx);
  1392     gpg.gpgme_release(import_ctx);
  1393     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1394     return PEP_STATUS_OK;
  1395 }
  1396 
  1397 PEP_STATUS pgp_find_keys(
  1398     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1399     )
  1400 {
  1401     gpgme_error_t gpgme_error;
  1402     gpgme_key_t key;
  1403 
  1404     assert(session);
  1405     assert(pattern);
  1406     assert(keylist);
  1407 
  1408     *keylist = NULL;
  1409 
  1410     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1411     gpgme_error = _GPGERR(gpgme_error);
  1412     switch (gpgme_error) {
  1413     case GPG_ERR_NO_ERROR:
  1414         break;
  1415     case GPG_ERR_INV_VALUE:
  1416         assert(0);
  1417         return PEP_UNKNOWN_ERROR;
  1418     default:
  1419         gpg.gpgme_op_keylist_end(session->ctx);
  1420         return PEP_GET_KEY_FAILED;
  1421     };
  1422 
  1423     stringlist_t *_keylist = new_stringlist(NULL);
  1424     stringlist_t *_k = _keylist;
  1425 
  1426     do {
  1427         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1428         gpgme_error = _GPGERR(gpgme_error);
  1429         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1430         switch (gpgme_error) {
  1431         case GPG_ERR_EOF:
  1432             break;
  1433         case GPG_ERR_NO_ERROR:
  1434             assert(key);
  1435             assert(key->subkeys);
  1436             char *fpr = key->subkeys->fpr;
  1437             assert(fpr);
  1438             _k = stringlist_add(_k, fpr);
  1439             assert(_k);
  1440             if (_k != NULL)
  1441                 break;
  1442         case GPG_ERR_ENOMEM:
  1443             free_stringlist(_keylist);
  1444             gpg.gpgme_op_keylist_end(session->ctx);
  1445             return PEP_OUT_OF_MEMORY;
  1446         default:
  1447             gpg.gpgme_op_keylist_end(session->ctx);
  1448             return PEP_UNKNOWN_ERROR;
  1449         };
  1450     } while (gpgme_error != GPG_ERR_EOF);
  1451 
  1452     gpg.gpgme_op_keylist_end(session->ctx);
  1453     if (_keylist->value == NULL) {
  1454         free_stringlist(_keylist);
  1455         _keylist = NULL;
  1456     }
  1457     *keylist = _keylist;
  1458     return PEP_STATUS_OK;
  1459 }
  1460 
  1461 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1462 {
  1463     gpgme_error_t gpgme_error;
  1464 
  1465     assert(session);
  1466     assert(pattern);
  1467 
  1468     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  1469         GPGME_EXPORT_MODE_EXTERN, NULL);
  1470     gpgme_error = _GPGERR(gpgme_error);
  1471     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1472     if (gpgme_error == GPG_ERR_NO_ERROR)
  1473         return PEP_STATUS_OK;
  1474     else
  1475         return PEP_CANNOT_SEND_KEY;
  1476 }
  1477 
  1478 PEP_STATUS pgp_get_key_rating(
  1479     PEP_SESSION session,
  1480     const char *fpr,
  1481     PEP_comm_type *comm_type
  1482     )
  1483 {
  1484     PEP_STATUS status = PEP_STATUS_OK;
  1485     gpgme_error_t gpgme_error;
  1486     gpgme_key_t key;
  1487 
  1488     assert(session);
  1489     assert(fpr);
  1490     assert(comm_type);
  1491 
  1492     *comm_type = PEP_ct_unknown;
  1493 
  1494     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1495     gpgme_error = _GPGERR(gpgme_error);
  1496     switch (gpgme_error) {
  1497     case GPG_ERR_NO_ERROR:
  1498         break;
  1499     case GPG_ERR_INV_VALUE:
  1500         assert(0);
  1501         return PEP_UNKNOWN_ERROR;
  1502     default:
  1503         return PEP_GET_KEY_FAILED;
  1504     };
  1505 
  1506     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1507     gpgme_error = _GPGERR(gpgme_error);
  1508     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1509 
  1510     if (key == NULL) {
  1511         gpg.gpgme_op_keylist_end(session->ctx);
  1512         return PEP_KEY_NOT_FOUND;
  1513     }
  1514 
  1515     switch (key->protocol) {
  1516     case GPGME_PROTOCOL_OpenPGP:
  1517     case GPGME_PROTOCOL_DEFAULT:
  1518         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1519         break;
  1520     case GPGME_PROTOCOL_CMS:
  1521         *comm_type = PEP_ct_CMS_unconfirmed;
  1522         break;
  1523     default:
  1524         *comm_type = PEP_ct_unknown;
  1525         gpg.gpgme_op_keylist_end(session->ctx);
  1526         return PEP_STATUS_OK;
  1527     }
  1528 
  1529     switch (gpgme_error) {
  1530     case GPG_ERR_EOF:
  1531         break;
  1532     case GPG_ERR_NO_ERROR:
  1533         assert(key);
  1534         assert(key->subkeys);
  1535         for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  1536             if (sk->length < 1024)
  1537                 *comm_type = PEP_ct_key_too_short;
  1538             else if (
  1539                 (
  1540                 (sk->pubkey_algo == GPGME_PK_RSA)
  1541                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  1542                 || (sk->pubkey_algo == GPGME_PK_RSA_S)
  1543                 )
  1544                 && sk->length == 1024
  1545                 )
  1546                 *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1547 
  1548             if (sk->invalid) {
  1549                 *comm_type = PEP_ct_key_b0rken;
  1550                 break;
  1551             }
  1552             if (sk->expired) {
  1553                 *comm_type = PEP_ct_key_expired;
  1554                 break;
  1555             }
  1556             if (sk->revoked) {
  1557                 *comm_type = PEP_ct_key_revoked;
  1558                 break;
  1559             }
  1560         }
  1561         break;
  1562     case GPG_ERR_ENOMEM:
  1563         gpg.gpgme_op_keylist_end(session->ctx);
  1564         *comm_type = PEP_ct_unknown;
  1565         return PEP_OUT_OF_MEMORY;
  1566     default:
  1567         gpg.gpgme_op_keylist_end(session->ctx);
  1568         return PEP_UNKNOWN_ERROR;
  1569     };
  1570 
  1571     gpg.gpgme_op_keylist_end(session->ctx);
  1572 
  1573     return status;
  1574 }
  1575 
  1576 static PEP_STATUS find_single_key(
  1577         PEP_SESSION session,
  1578         const char *fpr,
  1579         gpgme_key_t *key
  1580     )
  1581 {
  1582     gpgme_error_t gpgme_error;
  1583 
  1584     *key = NULL;
  1585 
  1586     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1587     gpgme_error = _GPGERR(gpgme_error);
  1588     switch (gpgme_error) {
  1589     case GPG_ERR_NO_ERROR:
  1590         break;
  1591     case GPG_ERR_INV_VALUE:
  1592         assert(0);
  1593         return PEP_UNKNOWN_ERROR;
  1594     default:
  1595         return PEP_GET_KEY_FAILED;
  1596     };
  1597 
  1598     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1599     gpgme_error = _GPGERR(gpgme_error);
  1600     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1601 
  1602     gpg.gpgme_op_keylist_end(session->ctx);
  1603 
  1604     return PEP_STATUS_OK;
  1605 }
  1606 
  1607 typedef struct _renew_state {
  1608     enum {
  1609         renew_command = 0,
  1610         renew_date,
  1611         renew_secret_key,
  1612         renew_command2,
  1613         renew_date2,
  1614         renew_quit,
  1615         renew_save,
  1616         renew_exit,
  1617         renew_error = -1
  1618     } state;
  1619     const char *date_ref;
  1620 } renew_state;
  1621 
  1622 static gpgme_error_t renew_fsm(
  1623         void *_handle,
  1624         gpgme_status_code_t statuscode,
  1625         const char *args,
  1626         int fd
  1627     )
  1628 {
  1629     renew_state *handle = _handle;
  1630 
  1631     switch (handle->state) {
  1632         case renew_command:
  1633             if (statuscode == GPGME_STATUS_GET_LINE) {
  1634                 assert(strcmp(args, "keyedit.prompt") == 0);
  1635                 if (strcmp(args, "keyedit.prompt")) {
  1636                     handle->state = renew_error;
  1637                     return GPG_ERR_GENERAL;
  1638                 }
  1639                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1640                 handle->state = renew_date;
  1641             }
  1642             break;
  1643 
  1644         case renew_date:
  1645             if (statuscode == GPGME_STATUS_GET_LINE) {
  1646                 assert(strcmp(args, "keygen.valid") == 0);
  1647                 if (strcmp(args, "keygen.valid")) {
  1648                     handle->state = renew_error;
  1649                     return GPG_ERR_GENERAL;
  1650                 }
  1651                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1652                 handle->state = renew_secret_key;
  1653             }
  1654             break;
  1655 
  1656         case renew_secret_key:
  1657             if (statuscode == GPGME_STATUS_GET_LINE) {
  1658                 assert(strcmp(args, "keyedit.prompt") == 0);
  1659                 if (strcmp(args, "keyedit.prompt")) {
  1660                     handle->state = renew_error;
  1661                     return GPG_ERR_GENERAL;
  1662                 }
  1663                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  1664                 handle->state = renew_command2;
  1665             }
  1666             break;
  1667 
  1668         case renew_command2:
  1669             if (statuscode == GPGME_STATUS_GET_LINE) {
  1670                 assert(strcmp(args, "keyedit.prompt") == 0);
  1671                 if (strcmp(args, "keyedit.prompt")) {
  1672                     handle->state = renew_error;
  1673                     return GPG_ERR_GENERAL;
  1674                 }
  1675                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1676                 handle->state = renew_date2;
  1677             }
  1678             break;
  1679 
  1680         case renew_date2:
  1681             if (statuscode == GPGME_STATUS_GET_LINE) {
  1682                 assert(strcmp(args, "keygen.valid") == 0);
  1683                 if (strcmp(args, "keygen.valid")) {
  1684                     handle->state = renew_error;
  1685                     return GPG_ERR_GENERAL;
  1686                 }
  1687                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1688                 handle->state = renew_quit;
  1689             }
  1690             break;
  1691 
  1692         case renew_quit:
  1693             if (statuscode == GPGME_STATUS_GET_LINE) {
  1694                 assert(strcmp(args, "keyedit.prompt") == 0);
  1695                 if (strcmp(args, "keyedit.prompt")) {
  1696                     handle->state = renew_error;
  1697                     return GPG_ERR_GENERAL;
  1698                 }
  1699                 gpg.gpgme_io_write(fd, "quit\n", 5);
  1700                 handle->state = renew_save;
  1701             }
  1702             break;
  1703 
  1704         case renew_save:
  1705             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1706                 assert(strcmp(args, "keyedit.save.okay") == 0);
  1707                 if (strcmp(args, "keyedit.save.okay")) {
  1708                     handle->state = renew_error;
  1709                     return GPG_ERR_GENERAL;
  1710                 }
  1711                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1712                 handle->state = renew_exit;
  1713             }
  1714             break;
  1715 
  1716         case renew_exit:
  1717             break;
  1718 
  1719         case renew_error:
  1720             return GPG_ERR_GENERAL;
  1721     }
  1722 
  1723     return GPG_ERR_NO_ERROR;
  1724 }
  1725 
  1726 static ssize_t _nullwriter(
  1727         void *_handle,
  1728         const void *buffer,
  1729         size_t size
  1730     )
  1731 {
  1732     return size;
  1733 }
  1734 
  1735 PEP_STATUS pgp_renew_key(
  1736         PEP_SESSION session,
  1737         const char *fpr,
  1738         const timestamp *ts
  1739     )
  1740 {
  1741     PEP_STATUS status = PEP_STATUS_OK;
  1742     gpgme_error_t gpgme_error;
  1743     gpgme_key_t key;
  1744     gpgme_data_t output;
  1745     renew_state handle;
  1746     char date_text[12];
  1747 
  1748     assert(session);
  1749     assert(fpr);
  1750 
  1751     memset(&handle, 0, sizeof(renew_state));
  1752     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  1753             ts->tm_mon + 1, ts->tm_mday);
  1754     handle.date_ref = date_text;
  1755 
  1756     status = find_single_key(session, fpr, &key);
  1757     if (status != PEP_STATUS_OK)
  1758         return status;
  1759 
  1760     struct gpgme_data_cbs data_cbs;
  1761     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  1762     data_cbs.write = _nullwriter;
  1763     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  1764 
  1765     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  1766             output);
  1767     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1768 
  1769     gpg.gpgme_data_release(output);
  1770     gpg.gpgme_key_unref(key);
  1771 
  1772     return PEP_STATUS_OK;
  1773 }
  1774 
  1775 typedef struct _revoke_state {
  1776     enum {
  1777         revoke_command = 0,
  1778         revoke_approve,
  1779         revoke_reason_code,
  1780         revoke_reason_text,
  1781         revoke_reason_ok,
  1782         revoke_quit,
  1783         revoke_save,
  1784         revoke_exit,
  1785         revoke_error = -1
  1786     } state;
  1787     const char *reason_ref;
  1788 } revoke_state;
  1789 
  1790 
  1791 /*** unused?
  1792 static bool isemptystring(const char *str)
  1793 {
  1794     if (str == NULL)
  1795         return true;
  1796 
  1797     for (; str; str++) {
  1798         if (*str != ' ' && *str != '\t' && *str != '\n')
  1799             return false;
  1800     }
  1801 
  1802     return true;
  1803 }
  1804 ***/
  1805 
  1806 
  1807 static gpgme_error_t revoke_fsm(
  1808         void *_handle,
  1809         gpgme_status_code_t statuscode,
  1810         const char *args,
  1811         int fd
  1812     )
  1813 {
  1814     revoke_state *handle = _handle;
  1815 
  1816     switch (handle->state) {
  1817         case revoke_command:
  1818             if (statuscode == GPGME_STATUS_GET_LINE) {
  1819                 assert(strcmp(args, "keyedit.prompt") == 0);
  1820                 if (strcmp(args, "keyedit.prompt")) {
  1821                     handle->state = revoke_error;
  1822                     return GPG_ERR_GENERAL;
  1823                 }
  1824                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  1825                 handle->state = revoke_approve;
  1826             }
  1827             break;
  1828 
  1829         case revoke_approve:
  1830             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1831                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  1832                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  1833                     handle->state = revoke_error;
  1834                     return GPG_ERR_GENERAL;
  1835                 }
  1836                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1837                 handle->state = revoke_reason_code;
  1838             }
  1839             break;
  1840 
  1841         case revoke_reason_code:
  1842             if (statuscode == GPGME_STATUS_GET_LINE) {
  1843                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  1844                 if (strcmp(args, "ask_revocation_reason.code")) {
  1845                     handle->state = revoke_error;
  1846                     return GPG_ERR_GENERAL;
  1847                 }
  1848                 gpg.gpgme_io_write(fd, "1\n", 2);
  1849                 handle->state = revoke_reason_text;
  1850             }
  1851             break;
  1852 
  1853         case revoke_reason_text:
  1854             if (statuscode == GPGME_STATUS_GET_LINE) {
  1855                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  1856                 if (strcmp(args, "ask_revocation_reason.text")) {
  1857                     handle->state = revoke_error;
  1858                     return GPG_ERR_GENERAL;
  1859                 }
  1860                 // BUG: issues when reason given
  1861                 // Assertion failed: (gpg->cmd.code), function command_handler,
  1862                 // file engine-gpg.c, line 662.
  1863                 //
  1864                 // if (isemptystring(handle->reason_ref)) {
  1865                     gpg.gpgme_io_write(fd, "\n", 1);
  1866                 // }
  1867                 // else {
  1868                 //     size_t len = strlen(handle->reason_ref);
  1869                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  1870                 //     if (handle->reason_ref[len - 1] == '\n')
  1871                 //         gpg.gpgme_io_write(fd, "\n", 1);
  1872                 //     else
  1873                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  1874                 // }
  1875                 handle->state = revoke_reason_ok;
  1876             }
  1877             break;
  1878 
  1879         case revoke_reason_ok:
  1880             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1881                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  1882                 if (strcmp(args, "ask_revocation_reason.okay")) {
  1883                     handle->state = revoke_error;
  1884                     return GPG_ERR_GENERAL;
  1885                 }
  1886                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1887                 handle->state = revoke_quit;
  1888             }
  1889             break;
  1890 
  1891         case revoke_quit:
  1892             if (statuscode == GPGME_STATUS_GET_LINE) {
  1893                 assert(strcmp(args, "keyedit.prompt") == 0);
  1894                 if (strcmp(args, "keyedit.prompt")) {
  1895                     handle->state = revoke_error;
  1896                     return GPG_ERR_GENERAL;
  1897                 }
  1898                 gpg.gpgme_io_write(fd, "quit\n", 5);
  1899                 handle->state = revoke_save;
  1900             }
  1901             break;
  1902 
  1903         case revoke_save:
  1904             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1905                 assert(strcmp(args, "keyedit.save.okay") == 0);
  1906                 if (strcmp(args, "keyedit.save.okay")) {
  1907                     handle->state = revoke_error;
  1908                     return GPG_ERR_GENERAL;
  1909                 }
  1910                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1911                 handle->state = revoke_exit;
  1912             }
  1913             break;
  1914 
  1915         case revoke_exit:
  1916             break;
  1917 
  1918         case revoke_error:
  1919             return GPG_ERR_GENERAL;
  1920     }
  1921 
  1922     return GPG_ERR_NO_ERROR;
  1923 }
  1924 
  1925 PEP_STATUS pgp_revoke_key(
  1926         PEP_SESSION session,
  1927         const char *fpr,
  1928         const char *reason
  1929     )
  1930 {
  1931     PEP_STATUS status = PEP_STATUS_OK;
  1932     gpgme_error_t gpgme_error;
  1933     gpgme_key_t key;
  1934     gpgme_data_t output;
  1935     revoke_state handle;
  1936 
  1937     assert(session);
  1938     assert(fpr);
  1939 
  1940     memset(&handle, 0, sizeof(revoke_state));
  1941     handle.reason_ref = reason;
  1942 
  1943     status = find_single_key(session, fpr, &key);
  1944     if (status != PEP_STATUS_OK)
  1945         return status;
  1946 
  1947     struct gpgme_data_cbs data_cbs;
  1948     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  1949     data_cbs.write = _nullwriter;
  1950     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  1951 
  1952     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  1953             output);
  1954     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1955 
  1956     gpg.gpgme_data_release(output);
  1957     gpg.gpgme_key_unref(key);
  1958 
  1959     return PEP_STATUS_OK;
  1960 }
  1961 
  1962 PEP_STATUS pgp_key_expired(
  1963         PEP_SESSION session,
  1964         const char *fpr,
  1965         const time_t when,
  1966         bool *expired
  1967     )
  1968 {
  1969     PEP_STATUS status = PEP_STATUS_OK;
  1970     gpgme_key_t key;
  1971 
  1972     assert(session);
  1973     assert(fpr);
  1974     assert(expired);
  1975 
  1976     *expired = false;
  1977 
  1978     status = find_single_key(session, fpr, &key);
  1979     if (status != PEP_STATUS_OK)
  1980         return status;
  1981 
  1982     if ((key && key->expired) ||
  1983         (key && key->subkeys && key->subkeys->expired))
  1984     {
  1985         // Already marked expired
  1986         *expired = 1;
  1987     }
  1988     else if (key)
  1989     {
  1990         // Detect if will be expired
  1991         // i.e. Check that keys capabilities will
  1992         // not be expired at given time.
  1993         gpgme_subkey_t _sk;
  1994         bool crt_available = false;
  1995         bool sgn_available = false;
  1996         bool enc_available = false;
  1997         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  1998             if (_sk->expires > when) // not expired at that date ?
  1999             {
  2000                 if (_sk->can_certify) crt_available = true;
  2001                 if (_sk->can_sign) sgn_available = true;
  2002                 if (_sk->can_encrypt) enc_available = true;
  2003                 // Authenticate is not used here.
  2004             }
  2005         }
  2006         if(!(crt_available && sgn_available && enc_available))
  2007         {
  2008             *expired = 1;
  2009         }
  2010     }
  2011     else
  2012     {
  2013         status = PEP_KEY_NOT_FOUND;
  2014     }
  2015 
  2016     gpg.gpgme_key_unref(key);
  2017     return status;
  2018 }
  2019 
  2020 PEP_STATUS pgp_key_revoked(
  2021         PEP_SESSION session,
  2022         const char *fpr,
  2023         bool *revoked
  2024     )
  2025 {
  2026     PEP_STATUS status = PEP_STATUS_OK;
  2027     gpgme_key_t key;
  2028 
  2029     assert(session);
  2030     assert(fpr);
  2031     assert(revoked);
  2032 
  2033     *revoked = false;
  2034 
  2035     status = find_single_key(session, fpr, &key);
  2036     if (status != PEP_STATUS_OK)
  2037         return status;
  2038 
  2039     if (key && key->subkeys)
  2040     {
  2041         *revoked = key->subkeys->revoked;
  2042     }
  2043     else
  2044     {
  2045         status = PEP_KEY_NOT_FOUND;
  2046     }
  2047 
  2048     gpg.gpgme_key_unref(key);
  2049     return status;
  2050 }
  2051 
  2052 PEP_STATUS pgp_binary(const char **path)
  2053 {
  2054     assert(path);
  2055     if (path == NULL)
  2056         return PEP_ILLEGAL_VALUE;
  2057 
  2058     *path = NULL;
  2059 
  2060     gpgme_engine_info_t info;
  2061     int err = gpg.gpgme_get_engine_info(&info);
  2062     assert(err == GPG_ERR_NO_ERROR);
  2063     if (err != GPG_ERR_NO_ERROR)
  2064         return PEP_OUT_OF_MEMORY;
  2065 
  2066     *path = info->file_name;
  2067 
  2068     return PEP_STATUS_OK;
  2069 }
  2070