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