src/pgp_gpg.c
author Krista Grothoff <krista@pep-project.org>
Tue, 15 Nov 2016 21:52:46 +0100
branchENGINE-74
changeset 1399 b77bc137c471
parent 1397 0a64816a6e37
child 1426 7a1d5065841b
permissions -rw-r--r--
stowing changes
     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_key_release = (gpgme_key_release_t)(intptr_t)
   329 			dlsym(gpgme, "gpgme_key_release");
   330 		assert(gpg.gpgme_key_release);
   331 
   332         gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
   333             dlsym(gpgme, "gpgme_op_edit");
   334         assert(gpg.gpgme_op_edit);
   335 
   336         gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
   337             dlsym(gpgme, "gpgme_io_write");
   338         assert(gpg.gpgme_io_write);
   339 
   340         gpg.version = gpg.gpgme_check(NULL);
   341         
   342         const char * const cLocal = setlocale(LC_ALL, NULL);
   343         if (!cLocal || (strcmp(cLocal, "C") == 0))
   344             setlocale(LC_ALL, "");
   345 
   346         gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
   347 #ifdef LC_MESSAGES // Windoze
   348         gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
   349 #endif
   350     }
   351 
   352     gpgme_error = gpg.gpgme_new(&session->ctx);
   353     gpgme_error = _GPGERR(gpgme_error);
   354     if (gpgme_error != GPG_ERR_NO_ERROR) {
   355         status = PEP_INIT_GPGME_INIT_FAILED;
   356         goto pep_error;
   357     }
   358     assert(session->ctx);
   359 
   360     gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
   361     gpgme_error = _GPGERR(gpgme_error);
   362     assert(gpgme_error == GPG_ERR_NO_ERROR);
   363 
   364     gpg.gpgme_set_armor(session->ctx, 1);
   365 
   366     return PEP_STATUS_OK;
   367 
   368 pep_error:
   369     pgp_release(session, in_first);
   370     return status;
   371 }
   372 
   373 void pgp_release(PEP_SESSION session, bool out_last)
   374 {
   375     if (session->ctx) {
   376         gpg.gpgme_release(session->ctx);
   377         session->ctx = NULL;
   378     }
   379 
   380     if (out_last)
   381         if (gpgme)
   382             dlclose(gpgme);
   383 }
   384 
   385 PEP_STATUS pgp_decrypt_and_verify(
   386     PEP_SESSION session, const char *ctext, size_t csize,
   387     const char *dsigtext, size_t dsigsize,
   388     char **ptext, size_t *psize, stringlist_t **keylist
   389     )
   390 {
   391     PEP_STATUS result;
   392     gpgme_error_t gpgme_error;
   393     gpgme_data_t cipher, plain;
   394     gpgme_data_type_t dt;
   395 
   396     stringlist_t *_keylist = NULL;
   397     //int i_key = 0;
   398 
   399     assert(session);
   400     assert(ctext);
   401     assert(csize);
   402     assert(ptext);
   403     assert(psize);
   404     assert(keylist);
   405 
   406     *ptext = NULL;
   407     *psize = 0;
   408     *keylist = NULL;
   409 
   410     gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
   411     gpgme_error = _GPGERR(gpgme_error);
   412     assert(gpgme_error == GPG_ERR_NO_ERROR);
   413     if (gpgme_error != GPG_ERR_NO_ERROR) {
   414         if (gpgme_error == GPG_ERR_ENOMEM)
   415             return PEP_OUT_OF_MEMORY;
   416         else
   417             return PEP_UNKNOWN_ERROR;
   418     }
   419 
   420     gpgme_error = gpg.gpgme_data_new(&plain);
   421     gpgme_error = _GPGERR(gpgme_error);
   422     assert(gpgme_error == GPG_ERR_NO_ERROR);
   423     if (gpgme_error != GPG_ERR_NO_ERROR) {
   424         gpg.gpgme_data_release(cipher);
   425         if (gpgme_error == GPG_ERR_ENOMEM)
   426             return PEP_OUT_OF_MEMORY;
   427         else
   428             return PEP_UNKNOWN_ERROR;
   429     }
   430 
   431     dt = gpg.gpgme_data_identify(cipher);
   432     switch (dt) {
   433     case GPGME_DATA_TYPE_PGP_SIGNED:
   434     case GPGME_DATA_TYPE_PGP_OTHER:
   435         gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
   436             plain);
   437         gpgme_error = _GPGERR(gpgme_error);
   438         assert(gpgme_error != GPG_ERR_INV_VALUE);
   439         assert(gpgme_error != GPG_ERR_NO_DATA);
   440 
   441         switch (gpgme_error) {
   442             case GPG_ERR_NO_ERROR:
   443             {
   444                 gpgme_verify_result_t gpgme_verify_result;
   445                 char *_buffer = NULL;
   446                 size_t reading;
   447                 size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
   448                 gpgme_signature_t gpgme_signature;
   449 
   450                 assert(length != -1);
   451                 gpg.gpgme_data_seek(plain, 0, SEEK_SET);
   452 
   453                 // TODO: make things less memory consuming
   454                 // the following algorithm allocates memory for the complete
   455                 // text
   456 
   457                 _buffer = malloc(length + 1);
   458                 assert(_buffer);
   459                 if (_buffer == NULL) {
   460                     gpg.gpgme_data_release(plain);
   461                     gpg.gpgme_data_release(cipher);
   462                     return PEP_OUT_OF_MEMORY;
   463                 }
   464 
   465                 reading = gpg.gpgme_data_read(plain, _buffer, length);
   466                 assert(length == reading);
   467 
   468 //                 if (dsigtext) {  // Is this safe to do?
   469 //                     gpgme_data_t sigdata;
   470 //                     gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
   471 //                                                 dsigsize, 0);
   472 //                     gpgme_op_verify(session->ctx, sigdata, plain, NULL);
   473 //                 }
   474                 
   475                 gpgme_verify_result =
   476                     gpg.gpgme_op_verify_result(session->ctx);
   477                 assert(gpgme_verify_result);
   478                 gpgme_signature = gpgme_verify_result->signatures;
   479 
   480                 if (!gpgme_signature && dsigtext) {
   481                     gpgme_data_t sigdata;
   482                     gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
   483                                                 dsigsize, 0);
   484                     gpgme_op_verify(session->ctx, sigdata, plain, NULL);
   485                     gpgme_verify_result =
   486                         gpg.gpgme_op_verify_result(session->ctx);
   487                     assert(gpgme_verify_result);
   488                     gpgme_signature = gpgme_verify_result->signatures;
   489                 }
   490                 
   491                 if (gpgme_signature) {
   492                     stringlist_t *k;
   493                     _keylist = new_stringlist(NULL);
   494                     assert(_keylist);
   495                     if (_keylist == NULL) {
   496                         gpg.gpgme_data_release(plain);
   497                         gpg.gpgme_data_release(cipher);
   498                         free(_buffer);
   499                         return PEP_OUT_OF_MEMORY;
   500                     }
   501                     k = _keylist;
   502 
   503                     result = PEP_DECRYPTED_AND_VERIFIED;
   504                     do {
   505                         switch (_GPGERR(gpgme_signature->status)) {
   506                         case GPG_ERR_NO_ERROR:
   507                         {
   508                             // Some versions of gpg returns signer's 
   509                             // signing subkey fingerprint instead of
   510                             // signer's primary key fingerprint.
   511                             // This is meant to get signer's primary 
   512                             // key fingerprint, using subkey's.
   513 
   514                             gpgme_key_t key = NULL;
   515 
   516                             gpgme_error = gpg.gpgme_get_key(session->ctx,
   517                                 gpgme_signature->fpr, &key, 0);
   518                             gpgme_error = _GPGERR(gpgme_error);
   519                             assert(gpgme_error != GPG_ERR_ENOMEM);
   520                             if (gpgme_error == GPG_ERR_ENOMEM) {
   521                                 free_stringlist(_keylist);
   522                                 gpg.gpgme_data_release(plain);
   523                                 gpg.gpgme_data_release(cipher);
   524                                 free(_buffer);
   525                                 return PEP_OUT_OF_MEMORY;
   526                             }
   527                             // Primary key is given as the first subkey
   528                             if (gpgme_error == GPG_ERR_NO_ERROR &&  
   529                                 key && key->subkeys && key->subkeys->fpr 
   530                                 && key->subkeys->fpr[0])
   531                             {
   532                                 k = stringlist_add(k, key->subkeys->fpr);
   533 
   534                                 gpg.gpgme_key_unref(key);
   535 
   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                             }
   544                             else 
   545                             {
   546                                 result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   547                                 break;
   548                             }
   549                             break;
   550                         }
   551                         case GPG_ERR_CERT_REVOKED:
   552                         case GPG_ERR_BAD_SIGNATURE:
   553                             result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   554                             break;
   555                         case GPG_ERR_SIG_EXPIRED:
   556                         case GPG_ERR_KEY_EXPIRED:
   557                         case GPG_ERR_NO_PUBKEY:
   558                             k = stringlist_add(k, gpgme_signature->fpr);
   559                             if (k == NULL) {
   560                                 free_stringlist(_keylist);
   561                                 gpg.gpgme_data_release(plain);
   562                                 gpg.gpgme_data_release(cipher);
   563                                 free(_buffer);
   564                                 return PEP_OUT_OF_MEMORY;
   565                             }
   566                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   567                                 result = PEP_DECRYPTED;
   568                             break;
   569                         case GPG_ERR_GENERAL:
   570                             break;
   571                         default:
   572                             if (result == PEP_DECRYPTED_AND_VERIFIED)
   573                                 result = PEP_DECRYPTED;
   574                             break;
   575                         }
   576                     } while ((gpgme_signature = gpgme_signature->next));
   577                 }
   578                 else {
   579                     result = PEP_DECRYPTED;
   580                 }
   581 
   582                 if (result == PEP_DECRYPTED_AND_VERIFIED
   583                     || result == PEP_DECRYPTED) {
   584                     *ptext = _buffer;
   585                     *psize = reading;
   586                     (*ptext)[*psize] = 0; // safeguard for naive users
   587                     *keylist = _keylist;
   588                 }
   589                 else {
   590                     free_stringlist(_keylist);
   591                     free(_buffer);
   592                 }
   593                 break;
   594             }
   595             case GPG_ERR_BAD_PASSPHRASE:
   596                 result = PEP_DECRYPT_NO_KEY;
   597                 break;
   598             case GPG_ERR_DECRYPT_FAILED:
   599             default:
   600             {
   601                 gpgme_decrypt_result_t gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
   602                 result = PEP_DECRYPT_NO_KEY;
   603 
   604                 if (gpgme_decrypt_result != NULL) {
   605                     if (gpgme_decrypt_result->unsupported_algorithm)
   606                         *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   607                     else
   608                         *keylist = new_stringlist("");
   609                     assert(*keylist);
   610                     if (*keylist == NULL) {
   611                         result = PEP_OUT_OF_MEMORY;
   612                         break;
   613                     }
   614                     stringlist_t *_keylist = *keylist;
   615                     for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   616                         _keylist = stringlist_add(_keylist, r->keyid);
   617                         assert(_keylist);
   618                         if (_keylist == NULL) {
   619                             free_stringlist(*keylist);
   620                             *keylist = NULL;
   621                             result = PEP_OUT_OF_MEMORY;
   622                             break;
   623                         }
   624                     }
   625                     if (result == PEP_OUT_OF_MEMORY)
   626                         break;
   627                 }
   628             }
   629         }
   630         break;
   631 
   632     default:
   633         result = PEP_DECRYPT_WRONG_FORMAT;
   634     }
   635 
   636     gpg.gpgme_data_release(plain);
   637     gpg.gpgme_data_release(cipher);
   638     return result;
   639 }
   640 
   641 PEP_STATUS pgp_verify_text(
   642     PEP_SESSION session, const char *text, size_t size,
   643     const char *signature, size_t sig_size, stringlist_t **keylist
   644     )
   645 {
   646     PEP_STATUS result;
   647     gpgme_error_t gpgme_error;
   648     gpgme_data_t d_text, d_sig;
   649     stringlist_t *_keylist;
   650 
   651     assert(session);
   652     assert(text);
   653     assert(size);
   654     assert(signature);
   655     assert(sig_size);
   656     assert(keylist);
   657 
   658     *keylist = NULL;
   659 
   660     gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   661     gpgme_error = _GPGERR(gpgme_error);
   662     assert(gpgme_error == GPG_ERR_NO_ERROR);
   663     if (gpgme_error != GPG_ERR_NO_ERROR) {
   664         if (gpgme_error == GPG_ERR_ENOMEM)
   665             return PEP_OUT_OF_MEMORY;
   666         else
   667             return PEP_UNKNOWN_ERROR;
   668     }
   669 
   670     gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   671     gpgme_error = _GPGERR(gpgme_error);
   672     assert(gpgme_error == GPG_ERR_NO_ERROR);
   673     if (gpgme_error != GPG_ERR_NO_ERROR) {
   674         gpg.gpgme_data_release(d_text);
   675         if (gpgme_error == GPG_ERR_ENOMEM)
   676             return PEP_OUT_OF_MEMORY;
   677         else
   678             return PEP_UNKNOWN_ERROR;
   679     }
   680 
   681     gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
   682     gpgme_error = _GPGERR(gpgme_error);
   683     assert(gpgme_error != GPG_ERR_INV_VALUE);
   684 
   685     switch (gpgme_error) {
   686     case GPG_ERR_NO_ERROR:
   687     {
   688         gpgme_verify_result_t gpgme_verify_result;
   689         gpgme_signature_t gpgme_signature;
   690 
   691         gpgme_verify_result =
   692             gpg.gpgme_op_verify_result(session->ctx);
   693         assert(gpgme_verify_result);
   694         gpgme_signature = gpgme_verify_result->signatures;
   695 
   696         if (gpgme_signature) {
   697             stringlist_t *k;
   698             _keylist = new_stringlist(NULL);
   699             assert(_keylist);
   700             if (_keylist == NULL) {
   701                 gpg.gpgme_data_release(d_text);
   702                 gpg.gpgme_data_release(d_sig);
   703                 return PEP_OUT_OF_MEMORY;
   704             }
   705             k = _keylist;
   706 
   707             result = PEP_VERIFIED;
   708             do {
   709                 gpgme_key_t key;
   710                 memset(&key,0,sizeof(key));
   711 
   712                 // GPGME may give subkey's fpr instead of primary key's fpr. 
   713                 // Therefore we ask for the primary fingerprint instead
   714                 // we assume that gpgme_get_key can find key by subkey's fpr
   715                 gpgme_error = gpg.gpgme_get_key(session->ctx,
   716                     gpgme_signature->fpr, &key, 0);
   717                 gpgme_error = _GPGERR(gpgme_error);
   718                 assert(gpgme_error != GPG_ERR_ENOMEM);
   719                 if (gpgme_error == GPG_ERR_ENOMEM) {
   720                     free_stringlist(_keylist);
   721                     gpg.gpgme_data_release(d_text);
   722                     gpg.gpgme_data_release(d_sig);
   723                     return PEP_OUT_OF_MEMORY;
   724                 }
   725                 // Primary key is given as the first subkey
   726                 if (gpgme_error == GPG_ERR_NO_ERROR &&  
   727                     key && key->subkeys && key->subkeys->fpr 
   728                     && key->subkeys->fpr[0])
   729                 {
   730                     k = stringlist_add(k, key->subkeys->fpr);
   731 
   732                     gpg.gpgme_key_unref(key);
   733 
   734                     if (k == NULL) {
   735                         free_stringlist(_keylist);
   736                         gpg.gpgme_data_release(d_text);
   737                         gpg.gpgme_data_release(d_sig);
   738                         return PEP_OUT_OF_MEMORY;
   739                     }
   740                 }
   741                 else {
   742                     result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   743                     break;
   744                 }
   745 
   746                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   747                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   748                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   749                         if (result == PEP_VERIFIED
   750                             || result == PEP_VERIFIED_AND_TRUSTED)
   751                             result = PEP_UNENCRYPTED;
   752                     }
   753                     else {
   754                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   755                         break;
   756                     }
   757                 }
   758                 else {
   759                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   760                         if (result == PEP_VERIFIED)
   761                             result = PEP_VERIFIED_AND_TRUSTED;
   762                     }
   763                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   764                         // good
   765                     }
   766                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   767                         result = PEP_VERIFY_NO_KEY;
   768                     }
   769                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   770                         if (result == PEP_VERIFIED
   771                             || result == PEP_VERIFIED_AND_TRUSTED)
   772                             result = PEP_UNENCRYPTED;
   773                     }
   774                     else {
   775                         // do nothing
   776                     }
   777                 }
   778             } while ((gpgme_signature = gpgme_signature->next));
   779             *keylist = _keylist;
   780         }
   781         else {
   782             result = PEP_UNENCRYPTED;
   783         }
   784         break;
   785     }
   786         break;
   787     case GPG_ERR_NO_DATA:
   788         result = PEP_DECRYPT_WRONG_FORMAT;
   789         break;
   790     case GPG_ERR_INV_VALUE:
   791     default:
   792         result = PEP_UNKNOWN_ERROR;
   793         break;
   794     }
   795 
   796     gpg.gpgme_data_release(d_text);
   797     gpg.gpgme_data_release(d_sig);
   798 
   799     return result;
   800 }
   801 
   802 PEP_STATUS pgp_encrypt_and_sign(
   803     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   804     size_t psize, char **ctext, size_t *csize
   805     )
   806 {
   807     PEP_STATUS result;
   808     gpgme_error_t gpgme_error;
   809     gpgme_data_t plain, cipher;
   810     gpgme_key_t *rcpt;
   811     gpgme_encrypt_flags_t flags;
   812     const stringlist_t *_keylist;
   813     int i, j;
   814 
   815     assert(session);
   816     assert(keylist);
   817     assert(ptext);
   818     assert(psize);
   819     assert(ctext);
   820     assert(csize);
   821 
   822     *ctext = NULL;
   823     *csize = 0;
   824 
   825     gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
   826     gpgme_error = _GPGERR(gpgme_error);
   827     assert(gpgme_error == GPG_ERR_NO_ERROR);
   828     if (gpgme_error != GPG_ERR_NO_ERROR) {
   829         if (gpgme_error == GPG_ERR_ENOMEM)
   830             return PEP_OUT_OF_MEMORY;
   831         else
   832             return PEP_UNKNOWN_ERROR;
   833     }
   834 
   835     gpgme_error = gpg.gpgme_data_new(&cipher);
   836     gpgme_error = _GPGERR(gpgme_error);
   837     assert(gpgme_error == GPG_ERR_NO_ERROR);
   838     if (gpgme_error != GPG_ERR_NO_ERROR) {
   839         gpg.gpgme_data_release(plain);
   840         if (gpgme_error == GPG_ERR_ENOMEM)
   841             return PEP_OUT_OF_MEMORY;
   842         else
   843             return PEP_UNKNOWN_ERROR;
   844     }
   845 
   846     rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
   847     assert(rcpt);
   848     if (rcpt == NULL) {
   849         gpg.gpgme_data_release(plain);
   850         gpg.gpgme_data_release(cipher);
   851         return PEP_OUT_OF_MEMORY;
   852     }
   853 
   854     gpg.gpgme_signers_clear(session->ctx);
   855 
   856     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
   857         assert(_keylist->value);
   858         gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
   859             &rcpt[i], 0);
   860         gpgme_error = _GPGERR(gpgme_error);
   861         assert(gpgme_error != GPG_ERR_ENOMEM);
   862 
   863         switch (gpgme_error) {
   864         case GPG_ERR_ENOMEM:
   865             for (j = 0; j<i; j++)
   866                 gpg.gpgme_key_unref(rcpt[j]);
   867             free(rcpt);
   868             gpg.gpgme_data_release(plain);
   869             gpg.gpgme_data_release(cipher);
   870             return PEP_OUT_OF_MEMORY;
   871         case GPG_ERR_NO_ERROR:
   872             if (i == 0) {
   873                 gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
   874                 _gpgme_error = _GPGERR(_gpgme_error);
   875                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
   876             }
   877             break;
   878         case GPG_ERR_EOF:
   879             for (j = 0; j<i; j++)
   880                 gpg.gpgme_key_unref(rcpt[j]);
   881             free(rcpt);
   882             gpg.gpgme_data_release(plain);
   883             gpg.gpgme_data_release(cipher);
   884             return PEP_KEY_NOT_FOUND;
   885         case GPG_ERR_AMBIGUOUS_NAME:
   886             for (j = 0; j<i; j++)
   887                 gpg.gpgme_key_unref(rcpt[j]);
   888             free(rcpt);
   889             gpg.gpgme_data_release(plain);
   890             gpg.gpgme_data_release(cipher);
   891             return PEP_KEY_HAS_AMBIG_NAME;
   892         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
   893             // FPR is not a fingerprint or key ID
   894             for (j = 0; j<i; j++)
   895                 gpg.gpgme_key_unref(rcpt[j]);
   896             free(rcpt);
   897             gpg.gpgme_data_release(plain);
   898             gpg.gpgme_data_release(cipher);
   899             return PEP_GET_KEY_FAILED;
   900         }
   901     }
   902 
   903     // TODO: remove that and replace with proper key management
   904     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
   905 
   906     gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
   907         plain, cipher);
   908     gpgme_error = _GPGERR(gpgme_error);
   909     switch (gpgme_error) {
   910     case GPG_ERR_NO_ERROR:
   911     {
   912         char *_buffer = NULL;
   913         size_t reading;
   914         size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
   915         assert(length != -1);
   916         gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
   917 
   918         // TODO: make things less memory consuming
   919         // the following algorithm allocates a buffer for the complete text
   920 
   921         _buffer = malloc(length + 1);
   922         assert(_buffer);
   923         if (_buffer == NULL) {
   924             for (j = 0; j<stringlist_length(keylist); j++)
   925                 gpg.gpgme_key_unref(rcpt[j]);
   926             free(rcpt);
   927             gpg.gpgme_data_release(plain);
   928             gpg.gpgme_data_release(cipher);
   929             return PEP_OUT_OF_MEMORY;
   930         }
   931 
   932         reading = gpg.gpgme_data_read(cipher, _buffer, length);
   933         assert(length == reading);
   934 
   935         *ctext = _buffer;
   936         *csize = reading;
   937         (*ctext)[*csize] = 0; // safeguard for naive users
   938         result = PEP_STATUS_OK;
   939         break;
   940     }
   941     default:
   942         result = PEP_UNKNOWN_ERROR;
   943     }
   944 
   945     for (j = 0; j<stringlist_length(keylist); j++)
   946         gpg.gpgme_key_unref(rcpt[j]);
   947     free(rcpt);
   948     gpg.gpgme_data_release(plain);
   949     gpg.gpgme_data_release(cipher);
   950     return result;
   951 }
   952 
   953 PEP_STATUS pgp_generate_keypair(
   954     PEP_SESSION session, pEp_identity *identity
   955     )
   956 {
   957     gpgme_error_t gpgme_error;
   958     char *parms;
   959     const char *template =
   960         "<GnupgKeyParms format=\"internal\">\n"
   961         "Key-Type: RSA\n"
   962         "Key-Length: 4096\n"
   963         "Subkey-Type: RSA\n"
   964         "Subkey-Length: 4096\n"
   965         "Name-Real: %s\n"
   966         "Name-Email: %s\n"
   967         /* "Passphrase: %s\n" */
   968         "Expire-Date: 1y\n"
   969         "</GnupgKeyParms>\n";
   970     int result;
   971     gpgme_genkey_result_t gpgme_genkey_result;
   972 
   973     assert(session);
   974     assert(identity);
   975     assert(identity->address);
   976     assert(identity->fpr == NULL || identity->fpr[0] == 0);
   977     assert(identity->username);
   978 
   979     parms = calloc(1, PARMS_MAX);
   980     assert(parms);
   981     if (parms == NULL)
   982         return PEP_OUT_OF_MEMORY;
   983 
   984     result = snprintf(parms, PARMS_MAX, template, identity->username,
   985         identity->address); // , session->passphrase);
   986     assert(result < PARMS_MAX);
   987     if (result >= PARMS_MAX) {
   988         free(parms);
   989         return PEP_BUFFER_TOO_SMALL;
   990     }
   991 
   992     gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
   993     gpgme_error = _GPGERR(gpgme_error);
   994     free(parms);
   995 
   996     switch (gpgme_error) {
   997     case GPG_ERR_NO_ERROR:
   998         break;
   999     case GPG_ERR_INV_VALUE:
  1000         return PEP_ILLEGAL_VALUE;
  1001     case GPG_ERR_GENERAL:
  1002         return PEP_CANNOT_CREATE_KEY;
  1003     default:
  1004         assert(0);
  1005         return PEP_UNKNOWN_ERROR;
  1006     }
  1007 
  1008     gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
  1009     assert(gpgme_genkey_result);
  1010     assert(gpgme_genkey_result->fpr);
  1011 
  1012     free(identity->fpr);
  1013     identity->fpr = strdup(gpgme_genkey_result->fpr);
  1014     if (identity->fpr == NULL)
  1015         return PEP_OUT_OF_MEMORY;
  1016 
  1017     return PEP_STATUS_OK;
  1018 }
  1019 
  1020 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
  1021 {
  1022     gpgme_error_t gpgme_error;
  1023     gpgme_key_t key;
  1024 
  1025     assert(session);
  1026     assert(fpr);
  1027 
  1028     gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
  1029     gpgme_error = _GPGERR(gpgme_error);
  1030     assert(gpgme_error != GPG_ERR_ENOMEM);
  1031     switch (gpgme_error) {
  1032     case GPG_ERR_NO_ERROR:
  1033         break;
  1034     case GPG_ERR_EOF:
  1035         return PEP_KEY_NOT_FOUND;
  1036     case GPG_ERR_INV_VALUE:
  1037         return PEP_ILLEGAL_VALUE;
  1038     case GPG_ERR_AMBIGUOUS_NAME:
  1039         return PEP_KEY_HAS_AMBIG_NAME;
  1040     case GPG_ERR_ENOMEM:
  1041         return PEP_OUT_OF_MEMORY;
  1042     default:
  1043         assert(0);
  1044         return PEP_UNKNOWN_ERROR;
  1045     }
  1046 
  1047     gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
  1048     gpgme_error = _GPGERR(gpgme_error);
  1049     gpg.gpgme_key_unref(key);
  1050     switch (gpgme_error) {
  1051     case GPG_ERR_NO_ERROR:
  1052         break;
  1053     case GPG_ERR_INV_VALUE:
  1054         assert(0);
  1055         return PEP_UNKNOWN_ERROR;
  1056     case GPG_ERR_NO_PUBKEY:
  1057         assert(0);
  1058         return PEP_KEY_NOT_FOUND;
  1059     case GPG_ERR_AMBIGUOUS_NAME:
  1060         assert(0);
  1061         return PEP_KEY_HAS_AMBIG_NAME;
  1062     default:
  1063         assert(0);
  1064         return PEP_UNKNOWN_ERROR;
  1065     }
  1066 
  1067     return PEP_STATUS_OK;
  1068 }
  1069 
  1070 PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
  1071                               size_t size, identity_list **private_idents)
  1072 {
  1073     gpgme_error_t gpgme_error;
  1074     gpgme_data_t dh;
  1075 
  1076     assert(session);
  1077     assert(key_data);
  1078    
  1079     if(private_idents) 
  1080         *private_idents = NULL;
  1081 
  1082     gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
  1083     gpgme_error = _GPGERR(gpgme_error);
  1084     assert(gpgme_error != GPG_ERR_ENOMEM);
  1085     switch (gpgme_error) {
  1086     case GPG_ERR_NO_ERROR:
  1087         break;
  1088     case GPG_ERR_ENOMEM:
  1089         return PEP_OUT_OF_MEMORY;
  1090     case GPG_ERR_INV_VALUE:
  1091         assert(0);
  1092         return PEP_UNKNOWN_ERROR;
  1093     default:
  1094         assert(0);
  1095         return PEP_UNKNOWN_ERROR;
  1096     }
  1097 
  1098     gpgme_import_result_t gpgme_import_result;
  1099 
  1100     gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
  1101     gpgme_error = _GPGERR(gpgme_error);
  1102     switch (gpgme_error) {
  1103     case GPG_ERR_NO_ERROR:
  1104         if(private_idents) 
  1105         {
  1106             gpgme_import_result =
  1107                 gpg.gpgme_op_import_result(session->ctx);
  1108             assert(gpgme_import_result);
  1109             if (!gpgme_import_result) {
  1110                 gpg.gpgme_data_release(dh);
  1111                 return PEP_UNKNOWN_ERROR;
  1112             }
  1113 
  1114             gpgme_import_status_t import;
  1115             for (import = gpgme_import_result->imports; 
  1116                  import; 
  1117                  import = import->next)
  1118              {
  1119                 if (import &&
  1120                     import->result == GPG_ERR_NO_ERROR &&
  1121                     import->status & GPGME_IMPORT_SECRET )
  1122                 {
  1123                     gpgme_key_t key = NULL;
  1124 
  1125                     gpgme_error = gpg.gpgme_get_key(session->ctx,
  1126                         import->fpr, &key, 0);
  1127                     gpgme_error = _GPGERR(gpgme_error);
  1128                     assert(gpgme_error != GPG_ERR_ENOMEM);
  1129                     if (gpgme_error == GPG_ERR_ENOMEM) {
  1130                         gpg.gpgme_data_release(dh);
  1131                         return PEP_OUT_OF_MEMORY;
  1132                     }
  1133                     
  1134                     if (gpgme_error == GPG_ERR_NO_ERROR &&  
  1135                         key && key->uids && 
  1136                         key->uids->email && key->uids->name)
  1137                     {
  1138                         pEp_identity *ident = new_identity(
  1139                              key->uids->email, import->fpr, NULL, key->uids->name);
  1140 
  1141                         gpg.gpgme_key_unref(key);
  1142 
  1143                         if (ident == NULL) {
  1144                             gpg.gpgme_data_release(dh);
  1145                             return PEP_OUT_OF_MEMORY;
  1146                         }
  1147 
  1148                         *private_idents = identity_list_add(*private_idents, ident);
  1149 
  1150                         if (*private_idents == NULL) {
  1151                             gpg.gpgme_data_release(dh);
  1152                             return PEP_OUT_OF_MEMORY;
  1153                         }
  1154                     }
  1155                     else 
  1156                     {
  1157                         gpg.gpgme_key_unref(key);
  1158                         gpg.gpgme_data_release(dh);
  1159                         return PEP_UNKNOWN_ERROR;
  1160                     }
  1161                 }
  1162             }
  1163         }
  1164         break;
  1165     case GPG_ERR_INV_VALUE:
  1166         assert(0);
  1167         gpg.gpgme_data_release(dh);
  1168         return PEP_UNKNOWN_ERROR;
  1169     case GPG_ERR_NO_DATA:
  1170         gpg.gpgme_data_release(dh);
  1171         return PEP_ILLEGAL_VALUE;
  1172     default:
  1173         assert(0);
  1174         gpg.gpgme_data_release(dh);
  1175         return PEP_UNKNOWN_ERROR;
  1176     }
  1177 
  1178     gpg.gpgme_data_release(dh);
  1179     return PEP_STATUS_OK;
  1180 }
  1181 
  1182 PEP_STATUS pgp_export_keydata(
  1183         PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
  1184         bool secret
  1185     )
  1186 {
  1187     gpgme_error_t gpgme_error;
  1188     gpgme_data_t dh;
  1189     size_t _size;
  1190     char *buffer;
  1191     int reading;
  1192 
  1193     assert(session);
  1194     assert(fpr);
  1195     assert(key_data);
  1196     assert(size);
  1197 
  1198     gpgme_error = gpg.gpgme_data_new(&dh);
  1199     gpgme_error = _GPGERR(gpgme_error);
  1200     assert(gpgme_error != GPG_ERR_ENOMEM);
  1201     switch (gpgme_error) {
  1202     case GPG_ERR_NO_ERROR:
  1203         break;
  1204     case GPG_ERR_ENOMEM:
  1205         return PEP_OUT_OF_MEMORY;
  1206     case GPG_ERR_INV_VALUE:
  1207         assert(0);
  1208         return PEP_UNKNOWN_ERROR;
  1209     default:
  1210         assert(0);
  1211         return PEP_UNKNOWN_ERROR;
  1212     }
  1213 
  1214     if (secret)
  1215         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1216             GPGME_EXPORT_MODE_SECRET, dh);
  1217     else
  1218         gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
  1219             GPGME_EXPORT_MODE_MINIMAL, dh);
  1220     gpgme_error = _GPGERR(gpgme_error);
  1221     switch (gpgme_error) {
  1222     case GPG_ERR_NO_ERROR:
  1223         break;
  1224     case GPG_ERR_EOF:
  1225         gpg.gpgme_data_release(dh);
  1226         return PEP_KEY_NOT_FOUND;
  1227     case GPG_ERR_INV_VALUE:
  1228         assert(0);
  1229         gpg.gpgme_data_release(dh);
  1230         return PEP_UNKNOWN_ERROR;
  1231     default:
  1232         assert(0);
  1233         gpg.gpgme_data_release(dh);
  1234         return PEP_UNKNOWN_ERROR;
  1235     };
  1236 
  1237     _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
  1238     assert(_size != -1);
  1239     gpg.gpgme_data_seek(dh, 0, SEEK_SET);
  1240 
  1241     buffer = malloc(_size + 1);
  1242     assert(buffer);
  1243     if (buffer == NULL) {
  1244         gpg.gpgme_data_release(dh);
  1245         return PEP_OUT_OF_MEMORY;
  1246     }
  1247 
  1248     reading = gpg.gpgme_data_read(dh, buffer, _size);
  1249     assert(_size == reading);
  1250 
  1251     // safeguard for the naive user
  1252     buffer[_size] = 0;
  1253 
  1254     *key_data = buffer;
  1255     *size = _size;
  1256 
  1257     gpg.gpgme_data_release(dh);
  1258     return PEP_STATUS_OK;
  1259 }
  1260 
  1261 PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern, 
  1262                             stringpair_list_t** keyinfo_list)
  1263 {    
  1264     gpgme_error_t gpgme_error;
  1265     assert(session);
  1266     assert(keyinfo_list);
  1267     
  1268     if (!session || !keyinfo_list)
  1269         return PEP_ILLEGAL_VALUE;
  1270     
  1271     *keyinfo_list = NULL;
  1272     
  1273     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1274     gpgme_error = _GPGERR(gpgme_error);
  1275     
  1276     switch(gpgme_error) {
  1277         case GPG_ERR_NO_ERROR:
  1278             break;
  1279         case GPG_ERR_INV_VALUE:
  1280             assert(0);
  1281             return PEP_UNKNOWN_ERROR;
  1282         default:
  1283             gpg.gpgme_op_keylist_end(session->ctx);
  1284             return PEP_GET_KEY_FAILED;        
  1285     };
  1286     
  1287     gpgme_key_t key;
  1288     stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
  1289     stringpair_list_t* list_curr = _keyinfo_list;
  1290     stringpair_t* pair = NULL;
  1291         
  1292     do { 
  1293         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1294         gpgme_error = _GPGERR(gpgme_error);
  1295       
  1296         switch(gpgme_error) {
  1297             case GPG_ERR_EOF:
  1298                 break;
  1299             case GPG_ERR_NO_ERROR:
  1300                 assert(key);
  1301                 assert(key->subkeys);
  1302                 if (!key || !key->subkeys)
  1303                     return PEP_GET_KEY_FAILED;
  1304 
  1305                 // first subkey is primary key
  1306                 char* fpr = key->subkeys->fpr;
  1307                 char* uid = key->uids->uid;
  1308 
  1309                 assert(fpr);
  1310                 assert(uid);
  1311                 if (!fpr)
  1312                     return PEP_GET_KEY_FAILED;
  1313                 
  1314                 if (key->subkeys->revoked)
  1315                     continue;
  1316                 
  1317                 pair = new_stringpair(fpr, uid);
  1318 
  1319                 assert(pair);
  1320                 
  1321                 if (pair) {
  1322                     list_curr = stringpair_list_add(list_curr, pair);
  1323                     pair = NULL;
  1324                     
  1325                     assert(list_curr);
  1326                     if (list_curr != NULL)
  1327                         break;
  1328                     else
  1329                         free_stringpair(pair);
  1330                 }
  1331                 // else fallthrough (list_curr or pair wasn't allocateable)
  1332             case GPG_ERR_ENOMEM:
  1333                 free_stringpair_list(_keyinfo_list);
  1334                 gpg.gpgme_op_keylist_end(session->ctx);
  1335                 return PEP_OUT_OF_MEMORY;
  1336             default:
  1337                 gpg.gpgme_op_keylist_end(session->ctx);
  1338                 return PEP_UNKNOWN_ERROR;
  1339         }
  1340     } while (gpgme_error != GPG_ERR_EOF);
  1341     
  1342     if (_keyinfo_list->value == NULL) {
  1343         free_stringpair_list(_keyinfo_list);
  1344         _keyinfo_list = NULL;
  1345     }
  1346     
  1347     *keyinfo_list = _keyinfo_list;
  1348     
  1349     return PEP_STATUS_OK;
  1350 }
  1351 
  1352 static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
  1353     gpgme_keylist_mode_t add_mode)
  1354 {
  1355     gpgme_error_t gpgme_error;
  1356     gpgme_keylist_mode_t mode;
  1357 
  1358     mode = gpg.gpgme_get_keylist_mode(session->ctx);
  1359 
  1360     mode &= ~remove_mode;
  1361     mode |= add_mode;
  1362 
  1363     gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
  1364     gpgme_error = _GPGERR(gpgme_error);
  1365     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1366 }
  1367 
  1368 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  1369 {
  1370     gpgme_error_t gpgme_error;
  1371     gpgme_key_t key;
  1372 
  1373     assert(session);
  1374     assert(pattern);
  1375 
  1376     _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
  1377 
  1378     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
  1379     gpgme_error = _GPGERR(gpgme_error);
  1380     switch (gpgme_error) {
  1381     case GPG_ERR_NO_ERROR:
  1382         break;
  1383     case GPG_ERR_INV_VALUE:
  1384         assert(0);
  1385         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1386         return PEP_UNKNOWN_ERROR;
  1387     default:
  1388         _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1389         return PEP_GET_KEY_FAILED;
  1390     };
  1391 
  1392     gpgme_ctx_t import_ctx;
  1393     gpgme_error = gpg.gpgme_new(&import_ctx);
  1394     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1395 
  1396     do {
  1397         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1398         gpgme_error = _GPGERR(gpgme_error);
  1399         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1400         switch (gpgme_error) {
  1401         case GPG_ERR_EOF:
  1402             break;
  1403         case GPG_ERR_NO_ERROR:
  1404         {
  1405             gpgme_error_t gpgme_error;
  1406             gpgme_key_t keys[2];
  1407 
  1408             keys[0] = key;
  1409             keys[1] = NULL;
  1410 
  1411             gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
  1412             gpgme_error = _GPGERR(gpgme_error);
  1413             gpg.gpgme_key_unref(key);
  1414             assert(gpgme_error != GPG_ERR_INV_VALUE);
  1415             assert(gpgme_error != GPG_ERR_CONFLICT);
  1416         }
  1417             break;
  1418         case GPG_ERR_ENOMEM:
  1419             gpg.gpgme_op_keylist_end(session->ctx);
  1420             gpg.gpgme_release(import_ctx);
  1421             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1422             return PEP_OUT_OF_MEMORY;
  1423         default:
  1424             gpg.gpgme_op_keylist_end(session->ctx);
  1425             gpg.gpgme_release(import_ctx);
  1426             _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1427             return PEP_UNKNOWN_ERROR;
  1428         };
  1429     } while (gpgme_error != GPG_ERR_EOF);
  1430 
  1431     gpg.gpgme_op_keylist_end(session->ctx);
  1432     gpg.gpgme_release(import_ctx);
  1433     _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
  1434     return PEP_STATUS_OK;
  1435 }
  1436 
  1437 
  1438 static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
  1439                             stringlist_t** keylist,
  1440                             int private_only) {
  1441     gpgme_error_t gpgme_error;
  1442     gpgme_key_t key;
  1443     
  1444     assert(session);
  1445     assert(pattern);
  1446     assert(keylist);
  1447     
  1448     *keylist = NULL;
  1449     
  1450     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
  1451     gpgme_error = _GPGERR(gpgme_error);
  1452     switch (gpgme_error) {
  1453         case GPG_ERR_NO_ERROR:
  1454             break;
  1455         case GPG_ERR_INV_VALUE:
  1456             assert(0);
  1457             return PEP_UNKNOWN_ERROR;
  1458         default:
  1459             gpg.gpgme_op_keylist_end(session->ctx);
  1460             return PEP_GET_KEY_FAILED;
  1461     };
  1462     
  1463     stringlist_t *_keylist = new_stringlist(NULL);
  1464     stringlist_t *_k = _keylist;
  1465     
  1466     do {
  1467         gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1468         gpgme_error = _GPGERR(gpgme_error);
  1469         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1470         switch (gpgme_error) {
  1471             case GPG_ERR_EOF:
  1472                 break;
  1473             case GPG_ERR_NO_ERROR:
  1474                 assert(key);
  1475                 assert(key->subkeys);
  1476                 char *fpr = key->subkeys->fpr;
  1477                 assert(fpr);
  1478                 _k = stringlist_add(_k, fpr);
  1479                 assert(_k);
  1480                 if (_k != NULL)
  1481                     break;
  1482             case GPG_ERR_ENOMEM:
  1483                 free_stringlist(_keylist);
  1484                 gpg.gpgme_op_keylist_end(session->ctx);
  1485                 return PEP_OUT_OF_MEMORY;
  1486             default:
  1487                 gpg.gpgme_op_keylist_end(session->ctx);
  1488                 return PEP_UNKNOWN_ERROR;
  1489         };
  1490     } while (gpgme_error != GPG_ERR_EOF);
  1491     
  1492     gpg.gpgme_op_keylist_end(session->ctx);
  1493     if (_keylist->value == NULL) {
  1494         free_stringlist(_keylist);
  1495         _keylist = NULL;
  1496     }
  1497     *keylist = _keylist;
  1498     return PEP_STATUS_OK;
  1499 }
  1500 
  1501 PEP_STATUS pgp_find_keys(
  1502     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1503     )
  1504 {
  1505     return _pgp_search_keys(session, pattern, keylist, 0);
  1506 }    
  1507 
  1508 PEP_STATUS pgp_find_private_keys(
  1509     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1510 )
  1511 {
  1512     return _pgp_search_keys(session, pattern, keylist, 1);
  1513 }
  1514 
  1515 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1516 {
  1517     gpgme_error_t gpgme_error;
  1518 
  1519     assert(session);
  1520     assert(pattern);
  1521 
  1522     gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
  1523         GPGME_EXPORT_MODE_EXTERN, NULL);
  1524     gpgme_error = _GPGERR(gpgme_error);
  1525     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1526     if (gpgme_error == GPG_ERR_NO_ERROR)
  1527         return PEP_STATUS_OK;
  1528     else
  1529         return PEP_CANNOT_SEND_KEY;
  1530 }
  1531 
  1532 PEP_STATUS pgp_get_key_rating(
  1533     PEP_SESSION session,
  1534     const char *fpr,
  1535     PEP_comm_type *comm_type
  1536     )
  1537 {
  1538     PEP_STATUS status = PEP_STATUS_OK;
  1539     gpgme_error_t gpgme_error;
  1540     gpgme_key_t key;
  1541 
  1542     assert(session);
  1543     assert(fpr);
  1544     assert(comm_type);
  1545 
  1546     *comm_type = PEP_ct_unknown;
  1547 
  1548     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1549     gpgme_error = _GPGERR(gpgme_error);
  1550     switch (gpgme_error) {
  1551     case GPG_ERR_NO_ERROR:
  1552         break;
  1553     case GPG_ERR_INV_VALUE:
  1554         assert(0);
  1555         return PEP_UNKNOWN_ERROR;
  1556     default:
  1557         return PEP_GET_KEY_FAILED;
  1558     };
  1559 
  1560     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
  1561     gpgme_error = _GPGERR(gpgme_error);
  1562     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1563 
  1564     if (key == NULL) {
  1565         gpg.gpgme_op_keylist_end(session->ctx);
  1566         return PEP_KEY_NOT_FOUND;
  1567     }
  1568 
  1569     switch (key->protocol) {
  1570     case GPGME_PROTOCOL_OpenPGP:
  1571     case GPGME_PROTOCOL_DEFAULT:
  1572         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1573         break;
  1574     case GPGME_PROTOCOL_CMS:
  1575         *comm_type = PEP_ct_CMS_unconfirmed;
  1576         break;
  1577     default:
  1578         *comm_type = PEP_ct_unknown;
  1579         gpg.gpgme_op_keylist_end(session->ctx);
  1580         return PEP_STATUS_OK;
  1581     }
  1582 
  1583     switch (gpgme_error) {
  1584     case GPG_ERR_EOF:
  1585         break;
  1586     case GPG_ERR_NO_ERROR:
  1587         assert(key);
  1588         assert(key->subkeys);
  1589         for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  1590             if (sk->length < 1024)
  1591                 *comm_type = PEP_ct_key_too_short;
  1592             else if (
  1593                 (
  1594                 (sk->pubkey_algo == GPGME_PK_RSA)
  1595                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  1596                 || (sk->pubkey_algo == GPGME_PK_RSA_S)
  1597                 )
  1598                 && sk->length == 1024
  1599                 )
  1600                 *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  1601 
  1602             if (sk->invalid) {
  1603                 *comm_type = PEP_ct_key_b0rken;
  1604                 break;
  1605             }
  1606             if (sk->expired) {
  1607                 *comm_type = PEP_ct_key_expired;
  1608                 break;
  1609             }
  1610             if (sk->revoked) {
  1611                 *comm_type = PEP_ct_key_revoked;
  1612                 break;
  1613             }
  1614         }
  1615         break;
  1616     case GPG_ERR_ENOMEM:
  1617         gpg.gpgme_op_keylist_end(session->ctx);
  1618         *comm_type = PEP_ct_unknown;
  1619         return PEP_OUT_OF_MEMORY;
  1620     default:
  1621         gpg.gpgme_op_keylist_end(session->ctx);
  1622         return PEP_UNKNOWN_ERROR;
  1623     };
  1624 
  1625     gpg.gpgme_op_keylist_end(session->ctx);
  1626 
  1627     return status;
  1628 }
  1629 
  1630 static PEP_STATUS find_single_key(
  1631         PEP_SESSION session,
  1632         const char *fpr,
  1633         gpgme_key_t *key
  1634     )
  1635 {
  1636     gpgme_error_t gpgme_error;
  1637 
  1638     *key = NULL;
  1639 
  1640     gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
  1641     gpgme_error = _GPGERR(gpgme_error);
  1642     switch (gpgme_error) {
  1643     case GPG_ERR_NO_ERROR:
  1644         break;
  1645     case GPG_ERR_INV_VALUE:
  1646         assert(0);
  1647         return PEP_UNKNOWN_ERROR;
  1648     default:
  1649         return PEP_GET_KEY_FAILED;
  1650     };
  1651 
  1652     gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
  1653     gpgme_error = _GPGERR(gpgme_error);
  1654     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1655 
  1656     gpg.gpgme_op_keylist_end(session->ctx);
  1657 
  1658     return PEP_STATUS_OK;
  1659 }
  1660 
  1661 typedef struct _renew_state {
  1662     enum {
  1663         renew_command = 0,
  1664         renew_date,
  1665         renew_secret_key,
  1666         renew_command2,
  1667         renew_date2,
  1668         renew_quit,
  1669         renew_save,
  1670         renew_exit,
  1671         renew_error = -1
  1672     } state;
  1673     const char *date_ref;
  1674 } renew_state;
  1675 
  1676 static gpgme_error_t renew_fsm(
  1677         void *_handle,
  1678         gpgme_status_code_t statuscode,
  1679         const char *args,
  1680         int fd
  1681     )
  1682 {
  1683     renew_state *handle = _handle;
  1684 
  1685     switch (handle->state) {
  1686         case renew_command:
  1687             if (statuscode == GPGME_STATUS_GET_LINE) {
  1688                 assert(strcmp(args, "keyedit.prompt") == 0);
  1689                 if (strcmp(args, "keyedit.prompt")) {
  1690                     handle->state = renew_error;
  1691                     return GPG_ERR_GENERAL;
  1692                 }
  1693                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1694                 handle->state = renew_date;
  1695             }
  1696             break;
  1697 
  1698         case renew_date:
  1699             if (statuscode == GPGME_STATUS_GET_LINE) {
  1700                 assert(strcmp(args, "keygen.valid") == 0);
  1701                 if (strcmp(args, "keygen.valid")) {
  1702                     handle->state = renew_error;
  1703                     return GPG_ERR_GENERAL;
  1704                 }
  1705                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1706                 handle->state = renew_secret_key;
  1707             }
  1708             break;
  1709 
  1710         case renew_secret_key:
  1711             if (statuscode == GPGME_STATUS_GET_LINE) {
  1712                 assert(strcmp(args, "keyedit.prompt") == 0);
  1713                 if (strcmp(args, "keyedit.prompt")) {
  1714                     handle->state = renew_error;
  1715                     return GPG_ERR_GENERAL;
  1716                 }
  1717                 gpg.gpgme_io_write(fd, "key 1\n", 6);
  1718                 handle->state = renew_command2;
  1719             }
  1720             break;
  1721 
  1722         case renew_command2:
  1723             if (statuscode == GPGME_STATUS_GET_LINE) {
  1724                 assert(strcmp(args, "keyedit.prompt") == 0);
  1725                 if (strcmp(args, "keyedit.prompt")) {
  1726                     handle->state = renew_error;
  1727                     return GPG_ERR_GENERAL;
  1728                 }
  1729                 gpg.gpgme_io_write(fd, "expire\n", 7);
  1730                 handle->state = renew_date2;
  1731             }
  1732             break;
  1733 
  1734         case renew_date2:
  1735             if (statuscode == GPGME_STATUS_GET_LINE) {
  1736                 assert(strcmp(args, "keygen.valid") == 0);
  1737                 if (strcmp(args, "keygen.valid")) {
  1738                     handle->state = renew_error;
  1739                     return GPG_ERR_GENERAL;
  1740                 }
  1741                 gpg.gpgme_io_write(fd, handle->date_ref, 11);
  1742                 handle->state = renew_quit;
  1743             }
  1744             break;
  1745 
  1746         case renew_quit:
  1747             if (statuscode == GPGME_STATUS_GET_LINE) {
  1748                 assert(strcmp(args, "keyedit.prompt") == 0);
  1749                 if (strcmp(args, "keyedit.prompt")) {
  1750                     handle->state = renew_error;
  1751                     return GPG_ERR_GENERAL;
  1752                 }
  1753                 gpg.gpgme_io_write(fd, "quit\n", 5);
  1754                 handle->state = renew_save;
  1755             }
  1756             break;
  1757 
  1758         case renew_save:
  1759             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1760                 assert(strcmp(args, "keyedit.save.okay") == 0);
  1761                 if (strcmp(args, "keyedit.save.okay")) {
  1762                     handle->state = renew_error;
  1763                     return GPG_ERR_GENERAL;
  1764                 }
  1765                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1766                 handle->state = renew_exit;
  1767             }
  1768             break;
  1769 
  1770         case renew_exit:
  1771             break;
  1772 
  1773         case renew_error:
  1774             return GPG_ERR_GENERAL;
  1775     }
  1776 
  1777     return GPG_ERR_NO_ERROR;
  1778 }
  1779 
  1780 static ssize_t _nullwriter(
  1781         void *_handle,
  1782         const void *buffer,
  1783         size_t size
  1784     )
  1785 {
  1786     return size;
  1787 }
  1788 
  1789 PEP_STATUS pgp_renew_key(
  1790         PEP_SESSION session,
  1791         const char *fpr,
  1792         const timestamp *ts
  1793     )
  1794 {
  1795     PEP_STATUS status = PEP_STATUS_OK;
  1796     gpgme_error_t gpgme_error;
  1797     gpgme_key_t key;
  1798     gpgme_data_t output;
  1799     renew_state handle;
  1800     char date_text[12];
  1801 
  1802     assert(session);
  1803     assert(fpr);
  1804 
  1805     memset(&handle, 0, sizeof(renew_state));
  1806     snprintf(date_text, 12, "%.4d-%.2d-%.2d\n", ts->tm_year + 1900,
  1807             ts->tm_mon + 1, ts->tm_mday);
  1808     handle.date_ref = date_text;
  1809 
  1810     status = find_single_key(session, fpr, &key);
  1811     if (status != PEP_STATUS_OK)
  1812         return status;
  1813 
  1814     struct gpgme_data_cbs data_cbs;
  1815     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  1816     data_cbs.write = _nullwriter;
  1817     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  1818 
  1819     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  1820             output);
  1821     assert(gpgme_error == GPG_ERR_NO_ERROR);
  1822 
  1823     gpg.gpgme_data_release(output);
  1824     gpg.gpgme_key_unref(key);
  1825 
  1826     return PEP_STATUS_OK;
  1827 }
  1828 
  1829 typedef struct _revoke_state {
  1830     enum {
  1831         revoke_command = 0,
  1832         revoke_approve,
  1833         revoke_reason_code,
  1834         revoke_reason_text,
  1835         revoke_reason_ok,
  1836         revoke_quit,
  1837         revoke_save,
  1838         revoke_exit,
  1839         revoke_error = -1
  1840     } state;
  1841     const char *reason_ref;
  1842 } revoke_state;
  1843 
  1844 
  1845 /*** unused?
  1846 static bool isemptystring(const char *str)
  1847 {
  1848     if (str == NULL)
  1849         return true;
  1850 
  1851     for (; str; str++) {
  1852         if (*str != ' ' && *str != '\t' && *str != '\n')
  1853             return false;
  1854     }
  1855 
  1856     return true;
  1857 }
  1858 ***/
  1859 
  1860 
  1861 static gpgme_error_t revoke_fsm(
  1862         void *_handle,
  1863         gpgme_status_code_t statuscode,
  1864         const char *args,
  1865         int fd
  1866     )
  1867 {
  1868     revoke_state *handle = _handle;
  1869 
  1870     switch (handle->state) {
  1871         case revoke_command:
  1872             if (statuscode == GPGME_STATUS_GET_LINE) {
  1873                 assert(strcmp(args, "keyedit.prompt") == 0);
  1874                 if (strcmp(args, "keyedit.prompt")) {
  1875                     handle->state = revoke_error;
  1876                     return GPG_ERR_GENERAL;
  1877                 }
  1878                 gpg.gpgme_io_write(fd, "revkey\n", 7);
  1879                 handle->state = revoke_approve;
  1880             }
  1881             break;
  1882 
  1883         case revoke_approve:
  1884             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1885                 assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  1886                 if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  1887                     handle->state = revoke_error;
  1888                     return GPG_ERR_GENERAL;
  1889                 }
  1890                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1891                 handle->state = revoke_reason_code;
  1892             }
  1893             break;
  1894 
  1895         case revoke_reason_code:
  1896             if (statuscode == GPGME_STATUS_GET_LINE) {
  1897                 assert(strcmp(args, "ask_revocation_reason.code") == 0);
  1898                 if (strcmp(args, "ask_revocation_reason.code")) {
  1899                     handle->state = revoke_error;
  1900                     return GPG_ERR_GENERAL;
  1901                 }
  1902                 gpg.gpgme_io_write(fd, "1\n", 2);
  1903                 handle->state = revoke_reason_text;
  1904             }
  1905             break;
  1906 
  1907         case revoke_reason_text:
  1908             if (statuscode == GPGME_STATUS_GET_LINE) {
  1909                 assert(strcmp(args, "ask_revocation_reason.text") == 0);
  1910                 if (strcmp(args, "ask_revocation_reason.text")) {
  1911                     handle->state = revoke_error;
  1912                     return GPG_ERR_GENERAL;
  1913                 }
  1914                 // BUG: issues when reason given
  1915                 // Assertion failed: (gpg->cmd.code), function command_handler,
  1916                 // file engine-gpg.c, line 662.
  1917                 //
  1918                 // if (isemptystring(handle->reason_ref)) {
  1919                     gpg.gpgme_io_write(fd, "\n", 1);
  1920                 // }
  1921                 // else {
  1922                 //     size_t len = strlen(handle->reason_ref);
  1923                 //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  1924                 //     if (handle->reason_ref[len - 1] == '\n')
  1925                 //         gpg.gpgme_io_write(fd, "\n", 1);
  1926                 //     else
  1927                 //         gpg.gpgme_io_write(fd, "\n\n", 2);
  1928                 // }
  1929                 handle->state = revoke_reason_ok;
  1930             }
  1931             break;
  1932 
  1933         case revoke_reason_ok:
  1934             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1935                 assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  1936                 if (strcmp(args, "ask_revocation_reason.okay")) {
  1937                     handle->state = revoke_error;
  1938                     return GPG_ERR_GENERAL;
  1939                 }
  1940                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1941                 handle->state = revoke_quit;
  1942             }
  1943             break;
  1944 
  1945         case revoke_quit:
  1946             if (statuscode == GPGME_STATUS_GET_LINE) {
  1947                 assert(strcmp(args, "keyedit.prompt") == 0);
  1948                 if (strcmp(args, "keyedit.prompt")) {
  1949                     handle->state = revoke_error;
  1950                     return GPG_ERR_GENERAL;
  1951                 }
  1952                 gpg.gpgme_io_write(fd, "quit\n", 5);
  1953                 handle->state = revoke_save;
  1954             }
  1955             break;
  1956 
  1957         case revoke_save:
  1958             if (statuscode == GPGME_STATUS_GET_BOOL) {
  1959                 assert(strcmp(args, "keyedit.save.okay") == 0);
  1960                 if (strcmp(args, "keyedit.save.okay")) {
  1961                     handle->state = revoke_error;
  1962                     return GPG_ERR_GENERAL;
  1963                 }
  1964                 gpg.gpgme_io_write(fd, "Y\n", 2);
  1965                 handle->state = revoke_exit;
  1966             }
  1967             break;
  1968 
  1969         case revoke_exit:
  1970             break;
  1971 
  1972         case revoke_error:
  1973             return GPG_ERR_GENERAL;
  1974     }
  1975 
  1976     return GPG_ERR_NO_ERROR;
  1977 }
  1978 
  1979 PEP_STATUS pgp_revoke_key(
  1980         PEP_SESSION session,
  1981         const char *fpr,
  1982         const char *reason
  1983     )
  1984 {
  1985     PEP_STATUS status = PEP_STATUS_OK;
  1986     gpgme_error_t gpgme_error;
  1987     gpgme_key_t key;
  1988     gpgme_data_t output;
  1989     revoke_state handle;
  1990 
  1991     assert(session);
  1992     assert(fpr);
  1993 
  1994     memset(&handle, 0, sizeof(revoke_state));
  1995     handle.reason_ref = reason;
  1996 
  1997     status = find_single_key(session, fpr, &key);
  1998     if (status != PEP_STATUS_OK)
  1999         return status;
  2000 
  2001     struct gpgme_data_cbs data_cbs;
  2002     memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  2003     data_cbs.write = _nullwriter;
  2004     gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  2005 
  2006     gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  2007             output);
  2008     assert(gpgme_error == GPG_ERR_NO_ERROR);
  2009 
  2010     gpg.gpgme_data_release(output);
  2011     gpg.gpgme_key_unref(key);
  2012 
  2013     return PEP_STATUS_OK;
  2014 }
  2015 
  2016 PEP_STATUS pgp_key_expired(
  2017         PEP_SESSION session,
  2018         const char *fpr,
  2019         const time_t when,
  2020         bool *expired
  2021     )
  2022 {
  2023     PEP_STATUS status = PEP_STATUS_OK;
  2024     gpgme_key_t key;
  2025 
  2026     assert(session);
  2027     assert(fpr);
  2028     assert(expired);
  2029 
  2030     *expired = false;
  2031 
  2032     status = find_single_key(session, fpr, &key);
  2033     if (status != PEP_STATUS_OK)
  2034         return status;
  2035 
  2036     if ((key && key->expired) ||
  2037         (key && key->subkeys && key->subkeys->expired))
  2038     {
  2039         // Already marked expired
  2040         *expired = 1;
  2041     }
  2042     else if (key)
  2043     {
  2044         // Detect if will be expired
  2045         // i.e. Check that keys capabilities will
  2046         // not be expired at given time.
  2047         gpgme_subkey_t _sk;
  2048         bool crt_available = false;
  2049         bool sgn_available = false;
  2050         bool enc_available = false;
  2051         for (_sk = key->subkeys; _sk; _sk = _sk->next) {
  2052             if (_sk->expires > when || _sk->expires == 0) // not expired at that date ?
  2053                                                           // Also, zero means "does not expire"
  2054             {
  2055                 if (_sk->can_certify) crt_available = true;
  2056                 if (_sk->can_sign) sgn_available = true;
  2057                 if (_sk->can_encrypt) enc_available = true;
  2058                 // Authenticate is not used here.
  2059             }
  2060         }
  2061         if(!(crt_available && sgn_available && enc_available))
  2062         {
  2063             *expired = 1;
  2064         }
  2065     }
  2066     else
  2067     {
  2068         status = PEP_KEY_NOT_FOUND;
  2069     }
  2070 
  2071     gpg.gpgme_key_unref(key);
  2072     return status;
  2073 }
  2074 
  2075 PEP_STATUS pgp_key_revoked(
  2076         PEP_SESSION session,
  2077         const char *fpr,
  2078         bool *revoked
  2079     )
  2080 {
  2081     PEP_STATUS status = PEP_STATUS_OK;
  2082     gpgme_key_t key;
  2083 
  2084     assert(session);
  2085     assert(fpr);
  2086     assert(revoked);
  2087 
  2088     *revoked = false;
  2089 
  2090     status = find_single_key(session, fpr, &key);
  2091     if (status != PEP_STATUS_OK)
  2092         return status;
  2093 
  2094     if (key && key->subkeys)
  2095     {
  2096         *revoked = key->subkeys->revoked;
  2097     }
  2098     else
  2099     {
  2100         status = PEP_KEY_NOT_FOUND;
  2101     }
  2102 
  2103     gpg.gpgme_key_unref(key);
  2104     return status;
  2105 }
  2106 
  2107 PEP_STATUS pgp_key_created(
  2108         PEP_SESSION session,
  2109         const char *fpr,
  2110         time_t *created
  2111     )
  2112 {
  2113     PEP_STATUS status = PEP_STATUS_OK;
  2114     gpgme_key_t key;
  2115 
  2116     assert(session);
  2117     assert(fpr);
  2118     assert(created);
  2119 
  2120     *created = 0;
  2121 
  2122     status = find_single_key(session, fpr, &key);
  2123     if (status != PEP_STATUS_OK)
  2124         return status;
  2125 
  2126     if (key && key->subkeys)
  2127     {
  2128         *created = (time_t) key->subkeys->timestamp;
  2129     }
  2130     else
  2131     {
  2132         status = PEP_KEY_NOT_FOUND;
  2133     }
  2134 
  2135     gpg.gpgme_key_unref(key);
  2136     return status;
  2137 }
  2138 
  2139 PEP_STATUS pgp_binary(const char **path)
  2140 {
  2141     assert(path);
  2142     if (path == NULL)
  2143         return PEP_ILLEGAL_VALUE;
  2144 
  2145     *path = NULL;
  2146 
  2147     gpgme_engine_info_t info;
  2148     int err = gpg.gpgme_get_engine_info(&info);
  2149     assert(err == GPG_ERR_NO_ERROR);
  2150     if (err != GPG_ERR_NO_ERROR)
  2151         return PEP_OUT_OF_MEMORY;
  2152 
  2153     *path = info->file_name;
  2154 
  2155     return PEP_STATUS_OK;
  2156 }
  2157 
  2158 PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
  2159         bool *has_private) {
  2160     PEP_STATUS status = PEP_STATUS_OK;
  2161     gpgme_key_t output_key;
  2162     gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
  2163     *has_private = false;
  2164     switch (gpgerr) {
  2165         case GPG_ERR_EOF:
  2166         case GPG_ERR_INV_VALUE:
  2167             status = PEP_KEY_NOT_FOUND;
  2168             break;
  2169         case GPG_ERR_AMBIGUOUS_NAME:
  2170             status = PEP_KEY_HAS_AMBIG_NAME;
  2171             break;
  2172         case GPG_ERR_NO_ERROR:
  2173             *has_private = true;
  2174             gpg.gpgme_key_release(output_key);
  2175             break;
  2176         case GPG_ERR_ENOMEM:
  2177             status = PEP_OUT_OF_MEMORY;
  2178             break;
  2179         default:
  2180             status = PEP_UNKNOWN_ERROR;
  2181             break;
  2182     }
  2183     return status;
  2184 }
  2185