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