src/pgp_gpg.c
author vb
Mon, 01 Sep 2014 19:30:30 +0200
changeset 27 096ad5873ef3
parent 26 843e629627bf
child 40 3e7aa2f67b7e
permissions -rw-r--r--
...
     1 #include "pgp_gpg.h"
     2 #include "pEp_internal.h"
     3 
     4 static bool ensure_keyserver()
     5 {
     6     static char buf[MAX_LINELENGTH];
     7     int n;
     8     FILE *f = fopen(gpg_conf(), "r");
     9 
    10     if (f != NULL) {
    11         while (!feof(f)) {
    12             char * s = fgets(buf, MAX_LINELENGTH, f);
    13             if (s && !feof(f)) {
    14                 char * t = strtok(s, " ");
    15                 if (t && strcmp(t, "keyserver") == 0) {
    16                     fclose(f);
    17                     return true;
    18                 }
    19             }
    20         }
    21         f = freopen(gpg_conf(), "a", f);
    22     }
    23     else {
    24         f = fopen(gpg_conf(), "w");
    25     }
    26 
    27     assert(f);
    28     if (f == NULL)
    29         return false;
    30 
    31     n = fprintf(f, "keyserver %s\n", DEFAULT_KEYSERVER);
    32     assert(n >= 0);
    33     fclose(f);
    34 
    35     return true;
    36 }
    37 
    38 PEP_STATUS pgp_init(PEP_SESSION session)
    39 {
    40     pEpSession *_session = (pEpSession *) session;
    41     gpgme_error_t gpgme_error;
    42     bool bResult = ensure_keyserver();
    43     assert(bResult);
    44 
    45     _session->gpgme = dlopen(LIBGPGME, RTLD_LAZY);
    46     if (_session->gpgme == NULL) {
    47         free(_session);
    48         return PEP_INIT_CANNOT_LOAD_GPGME;
    49     }
    50 
    51     memset(&(_session->gpg), 0, sizeof(struct gpg_s));
    52 
    53     _session->gpg.gpgme_set_locale
    54         = (gpgme_set_locale_t) (intptr_t) dlsym(_session->gpgme,
    55         "gpgme_set_locale");
    56     assert(_session->gpg.gpgme_set_locale);
    57 
    58     _session->gpg.gpgme_check
    59         = (gpgme_check_version_t) (intptr_t) dlsym(_session->gpgme,
    60         "gpgme_check_version");
    61     assert(_session->gpg.gpgme_check);
    62 
    63     _session->gpg.gpgme_new
    64         = (gpgme_new_t) (intptr_t) dlsym(_session->gpgme, "gpgme_new");
    65     assert(_session->gpg.gpgme_new);
    66 
    67     _session->gpg.gpgme_release
    68         = (gpgme_release_t) (intptr_t) dlsym(_session->gpgme, "gpgme_release");
    69     assert(_session->gpg.gpgme_release);
    70 
    71     _session->gpg.gpgme_set_protocol
    72         = (gpgme_set_protocol_t) (intptr_t) dlsym(_session->gpgme,
    73         "gpgme_set_protocol");
    74     assert(_session->gpg.gpgme_set_protocol);
    75 
    76     _session->gpg.gpgme_set_armor
    77         = (gpgme_set_armor_t) (intptr_t) dlsym(_session->gpgme,
    78         "gpgme_set_armor");
    79     assert(_session->gpg.gpgme_set_armor);
    80 
    81     _session->gpg.gpgme_data_new
    82         = (gpgme_data_new_t) (intptr_t) dlsym(_session->gpgme,
    83         "gpgme_data_new");
    84     assert(_session->gpg.gpgme_data_new);
    85 
    86     _session->gpg.gpgme_data_new_from_mem
    87         = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(_session->gpgme,
    88         "gpgme_data_new_from_mem");
    89     assert(_session->gpg.gpgme_data_new_from_mem);
    90 
    91     _session->gpg.gpgme_data_release
    92         = (gpgme_data_release_t) (intptr_t) dlsym(_session->gpgme,
    93         "gpgme_data_release");
    94     assert(_session->gpg.gpgme_data_release);
    95 
    96     _session->gpg.gpgme_data_identify
    97         = (gpgme_data_identify_t) (intptr_t) dlsym(_session->gpgme,
    98         "gpgme_data_identify");
    99     assert(_session->gpg.gpgme_data_identify);
   100     _session->gpg.gpgme_data_seek
   101         = (gpgme_data_seek_t) (intptr_t) dlsym(_session->gpgme,
   102         "gpgme_data_seek");
   103     assert(_session->gpg.gpgme_data_seek);
   104 
   105     _session->gpg.gpgme_data_read
   106         = (gpgme_data_read_t) (intptr_t) dlsym(_session->gpgme,
   107         "gpgme_data_read");
   108     assert(_session->gpg.gpgme_data_read);
   109 
   110     _session->gpg.gpgme_op_decrypt
   111         = (gpgme_op_decrypt_t) (intptr_t) dlsym(_session->gpgme,
   112         "gpgme_op_decrypt");
   113     assert(_session->gpg.gpgme_op_decrypt);
   114 
   115     _session->gpg.gpgme_op_verify
   116         = (gpgme_op_verify_t) (intptr_t) dlsym(_session->gpgme,
   117         "gpgme_op_verify");
   118     assert(_session->gpg.gpgme_op_verify);
   119 
   120     _session->gpg.gpgme_op_decrypt_verify
   121         = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(_session->gpgme,
   122         "gpgme_op_decrypt_verify");
   123     assert(_session->gpg.gpgme_op_decrypt_verify);
   124 
   125     _session->gpg.gpgme_op_decrypt_result
   126         = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(_session->gpgme,
   127         "gpgme_op_decrypt_result");
   128     assert(_session->gpg.gpgme_op_decrypt_result);
   129 
   130     _session->gpg.gpgme_op_encrypt_sign
   131         = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(_session->gpgme,
   132         "gpgme_op_encrypt_sign");
   133     assert(_session->gpg.gpgme_op_encrypt_sign);
   134 
   135     _session->gpg.gpgme_op_verify_result
   136         = (gpgme_op_verify_result_t) (intptr_t) dlsym(_session->gpgme,
   137         "gpgme_op_verify_result");
   138     assert(_session->gpg.gpgme_op_verify_result);
   139 
   140     _session->gpg.gpgme_signers_clear
   141         = (gpgme_signers_clear_t) (intptr_t) dlsym(_session->gpgme,
   142         "gpgme_signers_clear");
   143     assert(_session->gpg.gpgme_signers_clear);
   144 
   145     _session->gpg.gpgme_signers_add
   146         = (gpgme_signers_add_t) (intptr_t) dlsym(_session->gpgme,
   147         "gpgme_signers_add");
   148     assert(_session->gpg.gpgme_signers_add);
   149     _session->gpg.gpgme_get_key
   150         = (gpgme_get_key_t) (intptr_t) dlsym(_session->gpgme, "gpgme_get_key");
   151     assert(_session->gpg.gpgme_get_key);
   152 
   153     _session->gpg.gpgme_op_genkey
   154         = (gpgme_op_genkey_t) (intptr_t) dlsym(_session->gpgme,
   155         "gpgme_op_genkey");
   156     assert(_session->gpg.gpgme_op_genkey);
   157 
   158     _session->gpg.gpgme_op_genkey_result
   159         = (gpgme_op_genkey_result_t) (intptr_t) dlsym(_session->gpgme,
   160         "gpgme_op_genkey_result");
   161     assert(_session->gpg.gpgme_op_genkey_result);
   162 
   163     _session->gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
   164         dlsym(_session->gpgme, "gpgme_op_delete");
   165     assert(_session->gpg.gpgme_op_delete);
   166 
   167     _session->gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
   168         dlsym(_session->gpgme, "gpgme_op_import");
   169     assert(_session->gpg.gpgme_op_import);
   170 
   171     _session->gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
   172         dlsym(_session->gpgme, "gpgme_op_export");
   173     assert(_session->gpg.gpgme_op_export);
   174 
   175     _session->gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
   176         dlsym(_session->gpgme, "gpgme_set_keylist_mode");
   177     assert(_session->gpg.gpgme_set_keylist_mode);
   178 
   179     _session->gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
   180         dlsym(_session->gpgme, "gpgme_get_keylist_mode");
   181     assert(_session->gpg.gpgme_get_keylist_mode);
   182 
   183     _session->gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
   184         dlsym(_session->gpgme, "gpgme_op_keylist_start");
   185     assert(_session->gpg.gpgme_op_keylist_start);
   186 
   187     _session->gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
   188         dlsym(_session->gpgme, "gpgme_op_keylist_next");
   189     assert(_session->gpg.gpgme_op_keylist_next);
   190 
   191     _session->gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
   192         dlsym(_session->gpgme, "gpgme_op_keylist_end");
   193     assert(_session->gpg.gpgme_op_keylist_end);
   194 
   195     _session->gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
   196         dlsym(_session->gpgme, "gpgme_op_import_keys");
   197     assert(_session->gpg.gpgme_op_import_keys);
   198 
   199     _session->gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
   200         dlsym(_session->gpgme, "gpgme_key_ref");
   201     assert(_session->gpg.gpgme_key_ref);
   202 
   203     _session->gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
   204         dlsym(_session->gpgme, "gpgme_key_unref");
   205     assert(_session->gpg.gpgme_key_unref);
   206 
   207     setlocale(LC_ALL, "");
   208     _session->version = _session->gpg.gpgme_check(NULL);
   209     _session->gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
   210 
   211     gpgme_error = _session->gpg.gpgme_new(&_session->ctx);
   212     if (gpgme_error != GPG_ERR_NO_ERROR) {
   213         dlclose(_session->gpgme);
   214         free(_session);
   215         return PEP_INIT_GPGME_INIT_FAILED;
   216     }
   217     assert(_session->ctx);
   218 
   219     gpgme_error = _session->gpg.gpgme_set_protocol(_session->ctx,
   220         GPGME_PROTOCOL_OpenPGP);
   221     assert(gpgme_error == GPG_ERR_NO_ERROR);
   222 
   223     _session->gpg.gpgme_set_armor(_session->ctx, 1);
   224 
   225     return PEP_STATUS_OK;
   226 }
   227 
   228 void pgp_release(PEP_SESSION session)
   229 {
   230     pEpSession *_session = (pEpSession *) session;
   231     if (_session->ctx)
   232         _session->gpg.gpgme_release(_session->ctx);
   233     _session->ctx = NULL;
   234     memset(&(_session->gpg), 0, sizeof(struct gpg_s));
   235     dlclose(_session->gpgme);
   236 }
   237 
   238 PEP_STATUS pgp_decrypt_and_verify(
   239     PEP_SESSION session, const char *ctext, size_t csize,
   240     char **ptext, size_t *psize, stringlist_t **keylist
   241     )
   242 {
   243     pEpSession *_session = (pEpSession *) session;
   244 
   245     PEP_STATUS result;
   246     gpgme_error_t gpgme_error;
   247     gpgme_data_t cipher, plain;
   248     gpgme_data_type_t dt;
   249 
   250     stringlist_t *_keylist = NULL;
   251     int i_key = 0;
   252 
   253     assert(_session);
   254     assert(ctext);
   255     assert(csize);
   256     assert(ptext);
   257     assert(psize);
   258     assert(keylist);
   259 
   260     *ptext = NULL;
   261     *psize = 0;
   262     *keylist = NULL;
   263 
   264     gpgme_error = _session->gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
   265     assert(gpgme_error == GPG_ERR_NO_ERROR);
   266     if (gpgme_error != GPG_ERR_NO_ERROR) {
   267         if (gpgme_error == GPG_ERR_ENOMEM)
   268             return PEP_OUT_OF_MEMORY;
   269         else
   270             return PEP_UNKNOWN_ERROR;
   271     }
   272 
   273     gpgme_error = _session->gpg.gpgme_data_new(&plain);
   274     assert(gpgme_error == GPG_ERR_NO_ERROR);
   275     if (gpgme_error != GPG_ERR_NO_ERROR) {
   276         _session->gpg.gpgme_data_release(cipher);
   277         if (gpgme_error == GPG_ERR_ENOMEM)
   278             return PEP_OUT_OF_MEMORY;
   279         else
   280             return PEP_UNKNOWN_ERROR;
   281     }
   282 
   283     dt = _session->gpg.gpgme_data_identify(cipher);
   284     switch (dt) {
   285     case GPGME_DATA_TYPE_PGP_SIGNED:
   286     case GPGME_DATA_TYPE_PGP_OTHER:
   287         gpgme_error = _session->gpg.gpgme_op_decrypt_verify(_session->ctx, cipher,
   288             plain);
   289         assert(gpgme_error != GPG_ERR_INV_VALUE);
   290         assert(gpgme_error != GPG_ERR_NO_DATA);
   291 
   292         switch (gpgme_error) {
   293         case GPG_ERR_NO_ERROR:
   294         {
   295             gpgme_verify_result_t gpgme_verify_result;
   296             char *_buffer = NULL;
   297             size_t reading;
   298             size_t length = _session->gpg.gpgme_data_seek(plain, 0, SEEK_END);
   299             gpgme_signature_t gpgme_signature;
   300 
   301             assert(length != -1);
   302             _session->gpg.gpgme_data_seek(plain, 0, SEEK_SET);
   303 
   304             // TODO: make things less memory consuming
   305             // the following algorithm allocates memory for the complete
   306             // text
   307 
   308             _buffer = malloc(length + 1);
   309             assert(_buffer);
   310             if (_buffer == NULL) {
   311                 _session->gpg.gpgme_data_release(plain);
   312                 _session->gpg.gpgme_data_release(cipher);
   313                 return PEP_OUT_OF_MEMORY;
   314             }
   315 
   316             reading = _session->gpg.gpgme_data_read(plain, _buffer, length);
   317             assert(length == reading);
   318 
   319             gpgme_verify_result =
   320                 _session->gpg.gpgme_op_verify_result(_session->ctx);
   321             assert(gpgme_verify_result);
   322             gpgme_signature = gpgme_verify_result->signatures;
   323 
   324             if (gpgme_signature) {
   325                 stringlist_t *k;
   326                 _keylist = new_stringlist(NULL);
   327                 assert(_keylist);
   328                 if (_keylist == NULL) {
   329                     _session->gpg.gpgme_data_release(plain);
   330                     _session->gpg.gpgme_data_release(cipher);
   331                     free(_buffer);
   332                     return PEP_OUT_OF_MEMORY;
   333                 }
   334                 k = _keylist;
   335 
   336                 result = PEP_DECRYPTED_AND_VERIFIED;
   337                 do {
   338                     switch (gpgme_signature->status) {
   339                     case GPG_ERR_NO_ERROR:
   340                         k = stringlist_add(k, gpgme_signature->fpr);
   341                         break;
   342                     case GPG_ERR_CERT_REVOKED:
   343                     case GPG_ERR_BAD_SIGNATURE:
   344                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   345                         break;
   346                     case GPG_ERR_SIG_EXPIRED:
   347                     case GPG_ERR_KEY_EXPIRED:
   348                     case GPG_ERR_NO_PUBKEY:
   349                         k = stringlist_add(k, gpgme_signature->fpr);
   350                         if (result == PEP_DECRYPTED_AND_VERIFIED)
   351                             result = PEP_DECRYPTED;
   352                         break;
   353                     case GPG_ERR_GENERAL:
   354                         break;
   355                     default:
   356                         if (result == PEP_DECRYPTED_AND_VERIFIED)
   357                             result = PEP_DECRYPTED;
   358                         break;
   359                     }
   360                 } while ((gpgme_signature = gpgme_signature->next));
   361             }
   362             else {
   363                 result = PEP_DECRYPTED;
   364             }
   365 
   366             if (result == PEP_DECRYPTED_AND_VERIFIED
   367                 || result == PEP_DECRYPTED) {
   368                 *ptext = _buffer;
   369                 *psize = reading;
   370                 (*ptext)[*psize] = 0; // safeguard for naive users
   371                 *keylist = _keylist;
   372             }
   373             else {
   374                 free_stringlist(_keylist);
   375                 free(_buffer);
   376             }
   377             break;
   378         }
   379         case GPG_ERR_DECRYPT_FAILED:
   380             result = PEP_DECRYPT_WRONG_FORMAT;
   381             break;
   382         case GPG_ERR_BAD_PASSPHRASE:
   383             NOT_IMPLEMENTED;
   384         default:
   385         {
   386             gpgme_decrypt_result_t gpgme_decrypt_result = _session->gpg.gpgme_op_decrypt_result(_session->ctx);
   387             result = PEP_DECRYPT_NO_KEY;
   388 
   389             if (gpgme_decrypt_result != NULL) {
   390                 if (gpgme_decrypt_result->unsupported_algorithm)
   391                     *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
   392                 else
   393                     *keylist = new_stringlist("");
   394                 assert(*keylist);
   395                 if (*keylist == NULL) {
   396                     result = PEP_OUT_OF_MEMORY;
   397                     break;
   398                 }
   399                 stringlist_t *_keylist = *keylist;
   400                 for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
   401                     _keylist = stringlist_add(_keylist, r->keyid);
   402                     assert(_keylist);
   403                     if (_keylist == NULL) {
   404                         free_stringlist(*keylist);
   405                         *keylist = NULL;
   406                         result = PEP_OUT_OF_MEMORY;
   407                         break;
   408                     }
   409                 }
   410                 if (result == PEP_OUT_OF_MEMORY)
   411                     break;
   412             }
   413         }
   414         }
   415         break;
   416 
   417     default:
   418         result = PEP_DECRYPT_WRONG_FORMAT;
   419     }
   420 
   421     _session->gpg.gpgme_data_release(plain);
   422     _session->gpg.gpgme_data_release(cipher);
   423     return result;
   424 }
   425 
   426 PEP_STATUS pgp_verify_text(
   427     PEP_SESSION session, const char *text, size_t size,
   428     const char *signature, size_t sig_size, stringlist_t **keylist
   429     )
   430 {
   431     pEpSession *_session = (pEpSession *) session;
   432 
   433     PEP_STATUS result;
   434     gpgme_error_t gpgme_error;
   435     gpgme_data_t d_text, d_sig;
   436     stringlist_t *_keylist;
   437 
   438     assert(session);
   439     assert(text);
   440     assert(size);
   441     assert(signature);
   442     assert(sig_size);
   443     assert(keylist);
   444 
   445     *keylist = NULL;
   446 
   447     gpgme_error = _session->gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
   448     assert(gpgme_error == GPG_ERR_NO_ERROR);
   449     if (gpgme_error != GPG_ERR_NO_ERROR) {
   450         if (gpgme_error == GPG_ERR_ENOMEM)
   451             return PEP_OUT_OF_MEMORY;
   452         else
   453             return PEP_UNKNOWN_ERROR;
   454     }
   455 
   456     gpgme_error = _session->gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
   457     assert(gpgme_error == GPG_ERR_NO_ERROR);
   458     if (gpgme_error != GPG_ERR_NO_ERROR) {
   459         _session->gpg.gpgme_data_release(d_text);
   460         if (gpgme_error == GPG_ERR_ENOMEM)
   461             return PEP_OUT_OF_MEMORY;
   462         else
   463             return PEP_UNKNOWN_ERROR;
   464     }
   465 
   466     gpgme_error = _session->gpg.gpgme_op_verify(_session->ctx, d_sig, d_text, NULL);
   467     assert(gpgme_error != GPG_ERR_INV_VALUE);
   468 
   469     switch (gpgme_error) {
   470     case GPG_ERR_NO_ERROR:
   471     {
   472         gpgme_verify_result_t gpgme_verify_result;
   473         gpgme_signature_t gpgme_signature;
   474 
   475         gpgme_verify_result =
   476             _session->gpg.gpgme_op_verify_result(_session->ctx);
   477         assert(gpgme_verify_result);
   478         gpgme_signature = gpgme_verify_result->signatures;
   479 
   480         if (gpgme_signature) {
   481             stringlist_t *k;
   482             _keylist = new_stringlist(NULL);
   483             assert(_keylist);
   484             if (_keylist == NULL) {
   485                 _session->gpg.gpgme_data_release(d_text);
   486                 _session->gpg.gpgme_data_release(d_sig);
   487                 return PEP_OUT_OF_MEMORY;
   488             }
   489             k = _keylist;
   490 
   491             result = PEP_VERIFIED;
   492             do {
   493                 k = stringlist_add(k, gpgme_signature->fpr);
   494                 if (k == NULL) {
   495                     free_stringlist(_keylist);
   496                     _session->gpg.gpgme_data_release(d_text);
   497                     _session->gpg.gpgme_data_release(d_sig);
   498                     return PEP_OUT_OF_MEMORY;
   499                 }
   500                 if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
   501                     if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
   502                         || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
   503                         if (result == PEP_VERIFIED
   504                             || result == PEP_VERIFIED_AND_TRUSTED)
   505                             result = PEP_UNENCRYPTED;
   506                     }
   507                     else {
   508                         result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   509                         break;
   510                     }
   511                 }
   512                 else {
   513                     if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
   514                         if (result == PEP_VERIFIED)
   515                             result = PEP_VERIFIED_AND_TRUSTED;
   516                     }
   517                     if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
   518                         // good
   519                     }
   520                     else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
   521                         result = PEP_VERIFY_NO_KEY;
   522                     }
   523                     else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
   524                         if (result == PEP_VERIFIED
   525                             || result == PEP_VERIFIED_AND_TRUSTED)
   526                             result = PEP_UNENCRYPTED;
   527                     }
   528                     else {
   529                         // do nothing
   530                     }
   531                 }
   532             } while ((gpgme_signature = gpgme_signature->next));
   533             *keylist = _keylist;
   534         }
   535         else {
   536             result = PEP_UNENCRYPTED;
   537         }
   538         break;
   539     }
   540         break;
   541     case GPG_ERR_NO_DATA:
   542         result = PEP_DECRYPT_WRONG_FORMAT;
   543         break;
   544     case GPG_ERR_INV_VALUE:
   545     default:
   546         result = PEP_UNKNOWN_ERROR;
   547         break;
   548     }
   549 
   550     _session->gpg.gpgme_data_release(d_text);
   551     _session->gpg.gpgme_data_release(d_sig);
   552 
   553     return result;
   554 }
   555 
   556 PEP_STATUS pgp_encrypt_and_sign(
   557     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   558     size_t psize, char **ctext, size_t *csize
   559     )
   560 {
   561     pEpSession *_session = (pEpSession *) session;
   562 
   563     PEP_STATUS result;
   564     gpgme_error_t gpgme_error;
   565     gpgme_data_t plain, cipher;
   566     gpgme_key_t *rcpt;
   567     gpgme_encrypt_flags_t flags;
   568     const stringlist_t *_keylist;
   569     int i, j;
   570 
   571     assert(_session);
   572     assert(keylist);
   573     assert(ptext);
   574     assert(psize);
   575     assert(ctext);
   576     assert(csize);
   577 
   578     *ctext = NULL;
   579     *csize = 0;
   580 
   581     gpgme_error = _session->gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
   582     assert(gpgme_error == GPG_ERR_NO_ERROR);
   583     if (gpgme_error != GPG_ERR_NO_ERROR) {
   584         if (gpgme_error == GPG_ERR_ENOMEM)
   585             return PEP_OUT_OF_MEMORY;
   586         else
   587             return PEP_UNKNOWN_ERROR;
   588     }
   589 
   590     gpgme_error = _session->gpg.gpgme_data_new(&cipher);
   591     assert(gpgme_error == GPG_ERR_NO_ERROR);
   592     if (gpgme_error != GPG_ERR_NO_ERROR) {
   593         _session->gpg.gpgme_data_release(plain);
   594         if (gpgme_error == GPG_ERR_ENOMEM)
   595             return PEP_OUT_OF_MEMORY;
   596         else
   597             return PEP_UNKNOWN_ERROR;
   598     }
   599 
   600     rcpt = (gpgme_key_t *) calloc(stringlist_length(keylist) + 1,
   601         sizeof(gpgme_key_t));
   602     assert(rcpt);
   603     if (rcpt == NULL) {
   604         _session->gpg.gpgme_data_release(plain);
   605         _session->gpg.gpgme_data_release(cipher);
   606         return PEP_OUT_OF_MEMORY;
   607     }
   608 
   609     _session->gpg.gpgme_signers_clear(_session->ctx);
   610 
   611     for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
   612         assert(_keylist->value);
   613         gpgme_error = _session->gpg.gpgme_get_key(_session->ctx, _keylist->value,
   614             &rcpt[i], 0);
   615         assert(gpgme_error != GPG_ERR_ENOMEM);
   616 
   617         switch (gpgme_error) {
   618         case GPG_ERR_ENOMEM:
   619             for (j = 0; j<i; j++)
   620                 _session->gpg.gpgme_key_unref(rcpt[j]);
   621             free(rcpt);
   622             _session->gpg.gpgme_data_release(plain);
   623             _session->gpg.gpgme_data_release(cipher);
   624             return PEP_OUT_OF_MEMORY;
   625         case GPG_ERR_NO_ERROR:
   626             if (i == 0) {
   627                 gpgme_error_t _gpgme_error = _session->gpg.gpgme_signers_add(_session->ctx, rcpt[0]);
   628                 assert(_gpgme_error == GPG_ERR_NO_ERROR);
   629             }
   630             break;
   631         case GPG_ERR_EOF:
   632             for (j = 0; j<i; j++)
   633                 _session->gpg.gpgme_key_unref(rcpt[j]);
   634             free(rcpt);
   635             _session->gpg.gpgme_data_release(plain);
   636             _session->gpg.gpgme_data_release(cipher);
   637             return PEP_KEY_NOT_FOUND;
   638         case GPG_ERR_AMBIGUOUS_NAME:
   639             for (j = 0; j<i; j++)
   640                 _session->gpg.gpgme_key_unref(rcpt[j]);
   641             free(rcpt);
   642             _session->gpg.gpgme_data_release(plain);
   643             _session->gpg.gpgme_data_release(cipher);
   644             return PEP_KEY_HAS_AMBIG_NAME;
   645         default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
   646             // FPR is not a fingerprint or key ID
   647             for (j = 0; j<i; j++)
   648                 _session->gpg.gpgme_key_unref(rcpt[j]);
   649             free(rcpt);
   650             _session->gpg.gpgme_data_release(plain);
   651             _session->gpg.gpgme_data_release(cipher);
   652             return PEP_GET_KEY_FAILED;
   653         }
   654     }
   655 
   656     // TODO: remove that and replace with proper key management
   657     flags = GPGME_ENCRYPT_ALWAYS_TRUST;
   658 
   659     gpgme_error = _session->gpg.gpgme_op_encrypt_sign(_session->ctx, rcpt, flags,
   660         plain, cipher);
   661     switch (gpgme_error) {
   662     case GPG_ERR_NO_ERROR:
   663     {
   664         char *_buffer = NULL;
   665         size_t reading;
   666         size_t length = _session->gpg.gpgme_data_seek(cipher, 0, SEEK_END);
   667         assert(length != -1);
   668         _session->gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
   669 
   670         // TODO: make things less memory consuming
   671         // the following algorithm allocates a buffer for the complete text
   672 
   673         _buffer = (char *) malloc(length + 1);
   674         assert(_buffer);
   675         if (_buffer == NULL) {
   676             for (j = 0; j<stringlist_length(keylist); j++)
   677                 _session->gpg.gpgme_key_unref(rcpt[j]);
   678             free(rcpt);
   679             _session->gpg.gpgme_data_release(plain);
   680             _session->gpg.gpgme_data_release(cipher);
   681             return PEP_OUT_OF_MEMORY;
   682         }
   683 
   684         reading = _session->gpg.gpgme_data_read(cipher, _buffer, length);
   685         assert(length == reading);
   686 
   687         *ctext = _buffer;
   688         *csize = reading;
   689         (*ctext)[*csize] = 0; // safeguard for naive users
   690         result = PEP_STATUS_OK;
   691         break;
   692     }
   693     default:
   694         result = PEP_UNKNOWN_ERROR;
   695     }
   696 
   697     for (j = 0; j<stringlist_length(keylist); j++)
   698         _session->gpg.gpgme_key_unref(rcpt[j]);
   699     free(rcpt);
   700     _session->gpg.gpgme_data_release(plain);
   701     _session->gpg.gpgme_data_release(cipher);
   702     return result;
   703 }
   704 
   705 PEP_STATUS pgp_generate_keypair(
   706     PEP_SESSION session, pEp_identity *identity
   707     )
   708 {
   709     pEpSession *_session = (pEpSession *) session;
   710     gpgme_error_t gpgme_error;
   711     char *parms;
   712     const char *template =
   713         "<GnupgKeyParms format=\"internal\">\n"
   714         "Key-Type: RSA\n"
   715         "Key-Length: 4096\n"
   716         "Name-Real: %s\n"
   717         "Name-Email: %s\n"
   718         /* "Passphrase: %s\n" */
   719         "Expire-Date: 1y\n"
   720         "</GnupgKeyParms>\n";
   721     int result;
   722     gpgme_genkey_result_t gpgme_genkey_result;
   723 
   724     assert(session);
   725     assert(identity);
   726     assert(identity->address);
   727     assert(identity->fpr == NULL);
   728     assert(identity->username);
   729 
   730     parms = calloc(1, PARMS_MAX);
   731     assert(parms);
   732     if (parms == NULL)
   733         return PEP_OUT_OF_MEMORY;
   734 
   735     result = snprintf(parms, PARMS_MAX, template, identity->username,
   736         identity->address); // , _session->passphrase);
   737     assert(result < PARMS_MAX);
   738     if (result >= PARMS_MAX) {
   739         free(parms);
   740         return PEP_BUFFER_TOO_SMALL;
   741     }
   742 
   743     gpgme_error = _session->gpg.gpgme_op_genkey(_session->ctx, parms, NULL, NULL);
   744     free(parms);
   745 
   746     switch (gpgme_error) {
   747     case GPG_ERR_NO_ERROR:
   748         break;
   749     case GPG_ERR_INV_VALUE:
   750         return PEP_ILLEGAL_VALUE;
   751     case GPG_ERR_GENERAL:
   752         return PEP_CANNOT_CREATE_KEY;
   753     default:
   754         assert(0);
   755         return PEP_UNKNOWN_ERROR;
   756     }
   757 
   758     gpgme_genkey_result = _session->gpg.gpgme_op_genkey_result(_session->ctx);
   759     assert(gpgme_genkey_result);
   760     assert(gpgme_genkey_result->fpr);
   761 
   762     identity->fpr = strdup(gpgme_genkey_result->fpr);
   763 
   764     return PEP_STATUS_OK;
   765 }
   766 
   767 PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
   768 {
   769     pEpSession *_session = (pEpSession *) session;
   770     gpgme_error_t gpgme_error;
   771     gpgme_key_t key;
   772 
   773     assert(session);
   774     assert(fpr);
   775 
   776     gpgme_error = _session->gpg.gpgme_get_key(_session->ctx, fpr, &key, 0);
   777     assert(gpgme_error != GPG_ERR_ENOMEM);
   778     switch (gpgme_error) {
   779     case GPG_ERR_NO_ERROR:
   780         break;
   781     case GPG_ERR_EOF:
   782         return PEP_KEY_NOT_FOUND;
   783     case GPG_ERR_INV_VALUE:
   784         return PEP_ILLEGAL_VALUE;
   785     case GPG_ERR_AMBIGUOUS_NAME:
   786         return PEP_KEY_HAS_AMBIG_NAME;
   787     case GPG_ERR_ENOMEM:
   788         return PEP_OUT_OF_MEMORY;
   789     default:
   790         assert(0);
   791         return PEP_UNKNOWN_ERROR;
   792     }
   793 
   794     gpgme_error = _session->gpg.gpgme_op_delete(_session->ctx, key, 1);
   795     _session->gpg.gpgme_key_unref(key);
   796     switch (gpgme_error) {
   797     case GPG_ERR_NO_ERROR:
   798         break;
   799     case GPG_ERR_INV_VALUE:
   800         assert(0);
   801         return PEP_UNKNOWN_ERROR;
   802     case GPG_ERR_NO_PUBKEY:
   803         assert(0);
   804         return PEP_KEY_NOT_FOUND;
   805     case GPG_ERR_AMBIGUOUS_NAME:
   806         assert(0);
   807         return PEP_KEY_HAS_AMBIG_NAME;
   808     default:
   809         assert(0);
   810         return PEP_UNKNOWN_ERROR;
   811     }
   812 
   813     return PEP_STATUS_OK;
   814 }
   815 
   816 PEP_STATUS pgp_import_key(PEP_SESSION session, const char *key_data, size_t size)
   817 {
   818     pEpSession *_session = (pEpSession *) session;
   819     gpgme_error_t gpgme_error;
   820     gpgme_data_t dh;
   821 
   822     assert(session);
   823     assert(key_data);
   824 
   825     gpgme_error = _session->gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
   826     assert(gpgme_error != GPG_ERR_ENOMEM);
   827     switch (gpgme_error) {
   828     case GPG_ERR_NO_ERROR:
   829         break;
   830     case GPG_ERR_ENOMEM:
   831         return PEP_OUT_OF_MEMORY;
   832     case GPG_ERR_INV_VALUE:
   833         assert(0);
   834         return PEP_UNKNOWN_ERROR;
   835     default:
   836         assert(0);
   837         return PEP_UNKNOWN_ERROR;
   838     }
   839 
   840     gpgme_error = _session->gpg.gpgme_op_import(_session->ctx, dh);
   841     switch (gpgme_error) {
   842     case GPG_ERR_NO_ERROR:
   843         break;
   844     case GPG_ERR_INV_VALUE:
   845         assert(0);
   846         _session->gpg.gpgme_data_release(dh);
   847         return PEP_UNKNOWN_ERROR;
   848     case GPG_ERR_NO_DATA:
   849         _session->gpg.gpgme_data_release(dh);
   850         return PEP_ILLEGAL_VALUE;
   851     default:
   852         assert(0);
   853         _session->gpg.gpgme_data_release(dh);
   854         return PEP_UNKNOWN_ERROR;
   855     }
   856 
   857     _session->gpg.gpgme_data_release(dh);
   858     return PEP_STATUS_OK;
   859 }
   860 
   861 PEP_STATUS pgp_export_key(
   862     PEP_SESSION session, const char *fpr, char **key_data, size_t *size
   863     )
   864 {
   865     pEpSession *_session = (pEpSession *) session;
   866     gpgme_error_t gpgme_error;
   867     gpgme_data_t dh;
   868     size_t _size;
   869     char *buffer;
   870     int reading;
   871 
   872     assert(session);
   873     assert(fpr);
   874     assert(key_data);
   875     assert(size);
   876 
   877     gpgme_error = _session->gpg.gpgme_data_new(&dh);
   878     assert(gpgme_error != GPG_ERR_ENOMEM);
   879     switch (gpgme_error) {
   880     case GPG_ERR_NO_ERROR:
   881         break;
   882     case GPG_ERR_ENOMEM:
   883         return PEP_OUT_OF_MEMORY;
   884     case GPG_ERR_INV_VALUE:
   885         assert(0);
   886         return PEP_UNKNOWN_ERROR;
   887     default:
   888         assert(0);
   889         return PEP_UNKNOWN_ERROR;
   890     }
   891 
   892     gpgme_error = _session->gpg.gpgme_op_export(_session->ctx, fpr,
   893         GPGME_EXPORT_MODE_MINIMAL, dh);
   894     switch (gpgme_error) {
   895     case GPG_ERR_NO_ERROR:
   896         break;
   897     case GPG_ERR_EOF:
   898         _session->gpg.gpgme_data_release(dh);
   899         return PEP_KEY_NOT_FOUND;
   900     case GPG_ERR_INV_VALUE:
   901         assert(0);
   902         _session->gpg.gpgme_data_release(dh);
   903         return PEP_UNKNOWN_ERROR;
   904     default:
   905         assert(0);
   906         _session->gpg.gpgme_data_release(dh);
   907         return PEP_UNKNOWN_ERROR;
   908     };
   909 
   910     _size = _session->gpg.gpgme_data_seek(dh, 0, SEEK_END);
   911     assert(_size != -1);
   912     _session->gpg.gpgme_data_seek(dh, 0, SEEK_SET);
   913 
   914     buffer = malloc(_size + 1);
   915     assert(buffer);
   916     if (buffer == NULL) {
   917         _session->gpg.gpgme_data_release(dh);
   918         return PEP_OUT_OF_MEMORY;
   919     }
   920 
   921     reading = _session->gpg.gpgme_data_read(dh, buffer, _size);
   922     assert(_size == reading);
   923 
   924     // safeguard for the naive user
   925     buffer[_size] = 0;
   926 
   927     *key_data = buffer;
   928     *size = _size;
   929 
   930     _session->gpg.gpgme_data_release(dh);
   931     return PEP_STATUS_OK;
   932 }
   933 
   934 static void _switch_mode(pEpSession *_session, gpgme_keylist_mode_t remove_mode,
   935     gpgme_keylist_mode_t add_mode)
   936 {
   937     gpgme_error_t gpgme_error;
   938     gpgme_keylist_mode_t mode;
   939 
   940     mode = _session->gpg.gpgme_get_keylist_mode(_session->ctx);
   941 
   942     mode &= ~remove_mode;
   943     mode |= add_mode;
   944 
   945     gpgme_error = _session->gpg.gpgme_set_keylist_mode(_session->ctx, mode);
   946     assert(gpgme_error == GPG_ERR_NO_ERROR);
   947 }
   948 
   949 PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
   950 {
   951     pEpSession *_session = (pEpSession *) session;
   952     gpgme_error_t gpgme_error;
   953     gpgme_key_t key;
   954 
   955     assert(session);
   956     assert(pattern);
   957 
   958     _switch_mode(_session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
   959 
   960     gpgme_error = _session->gpg.gpgme_op_keylist_start(_session->ctx, pattern, 0);
   961     switch (gpgme_error) {
   962     case GPG_ERR_NO_ERROR:
   963         break;
   964     case GPG_ERR_INV_VALUE:
   965         assert(0);
   966         _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
   967             GPGME_KEYLIST_MODE_LOCAL);
   968         return PEP_UNKNOWN_ERROR;
   969     default:
   970         _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
   971             GPGME_KEYLIST_MODE_LOCAL);
   972         return PEP_GET_KEY_FAILED;
   973     };
   974 
   975     do {
   976         gpgme_error = _session->gpg.gpgme_op_keylist_next(_session->ctx, &key);
   977         assert(gpgme_error != GPG_ERR_INV_VALUE);
   978         switch (gpgme_error) {
   979         case GPG_ERR_EOF:
   980             break;
   981         case GPG_ERR_NO_ERROR:
   982         {
   983             gpgme_error_t gpgme_error;
   984             gpgme_key_t keys[2];
   985 
   986             keys[0] = key;
   987             keys[1] = NULL;
   988 
   989             gpgme_error = _session->gpg.gpgme_op_import_keys(_session->ctx, keys);
   990             _session->gpg.gpgme_key_unref(key);
   991             assert(gpgme_error != GPG_ERR_INV_VALUE);
   992             assert(gpgme_error != GPG_ERR_CONFLICT);
   993         }
   994             break;
   995         case GPG_ERR_ENOMEM:
   996             _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
   997                 GPGME_KEYLIST_MODE_LOCAL);
   998             _session->gpg.gpgme_op_keylist_end(_session->ctx);
   999             return PEP_OUT_OF_MEMORY;
  1000         default:
  1001             // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
  1002             // reading first key
  1003 #ifndef NDEBUG
  1004             fprintf(stderr, "warning: unknown result 0x%x of"
  1005                 " gpgme_op_keylist_next()\n", gpgme_error);
  1006 #endif
  1007             gpgme_error = GPG_ERR_EOF;
  1008             break;
  1009         };
  1010     } while (gpgme_error != GPG_ERR_EOF);
  1011 
  1012     _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1013     _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
  1014         GPGME_KEYLIST_MODE_LOCAL);
  1015     return PEP_STATUS_OK;
  1016 }
  1017 
  1018 PEP_STATUS pgp_find_keys(
  1019     PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1020     )
  1021 {
  1022     pEpSession *_session = (pEpSession *) session;
  1023     gpgme_error_t gpgme_error;
  1024     gpgme_key_t key;
  1025     stringlist_t *_keylist;
  1026     char *fpr;
  1027 
  1028     assert(session);
  1029     assert(pattern);
  1030     assert(keylist);
  1031 
  1032     *keylist = NULL;
  1033 
  1034     gpgme_error = _session->gpg.gpgme_op_keylist_start(_session->ctx, pattern, 0);
  1035     switch (gpgme_error) {
  1036     case GPG_ERR_NO_ERROR:
  1037         break;
  1038     case GPG_ERR_INV_VALUE:
  1039         assert(0);
  1040         return PEP_UNKNOWN_ERROR;
  1041     default:
  1042         return PEP_GET_KEY_FAILED;
  1043     };
  1044 
  1045     _keylist = new_stringlist(NULL);
  1046     stringlist_t *_k = _keylist;
  1047 
  1048     do {
  1049         gpgme_error = _session->gpg.gpgme_op_keylist_next(_session->ctx, &key);
  1050         assert(gpgme_error != GPG_ERR_INV_VALUE);
  1051         switch (gpgme_error) {
  1052         case GPG_ERR_EOF:
  1053             break;
  1054         case GPG_ERR_NO_ERROR:
  1055             assert(key);
  1056             assert(key->subkeys);
  1057             fpr = key->subkeys->fpr;
  1058             assert(fpr);
  1059             _k = stringlist_add(_k, fpr);
  1060             assert(_k);
  1061             if (_k != NULL)
  1062                 break;
  1063         case GPG_ERR_ENOMEM:
  1064             free_stringlist(_keylist);
  1065             _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1066             return PEP_OUT_OF_MEMORY;
  1067         default:
  1068             // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
  1069             // reading first key
  1070 #ifndef NDEBUG
  1071             fprintf(stderr, "warning: unknown result 0x%x of"
  1072                 " gpgme_op_keylist_next()\n", gpgme_error);
  1073 #endif
  1074             gpgme_error = GPG_ERR_EOF;
  1075             break;
  1076         };
  1077     } while (gpgme_error != GPG_ERR_EOF);
  1078 
  1079     _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1080     *keylist = _keylist;
  1081     return PEP_STATUS_OK;
  1082 }
  1083 
  1084 PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  1085 {
  1086     pEpSession *_session = (pEpSession *) session;
  1087     gpgme_error_t gpgme_error;
  1088 
  1089     assert(session);
  1090     assert(pattern);
  1091 
  1092     gpgme_error = _session->gpg.gpgme_op_export(_session->ctx, pattern,
  1093         GPGME_EXPORT_MODE_EXTERN, NULL);
  1094     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1095     if (gpgme_error == GPG_ERR_NO_ERROR)
  1096         return PEP_STATUS_OK;
  1097     else
  1098         return PEP_CANNOT_SEND_KEY;
  1099 }
  1100 
  1101 
  1102 PEP_STATUS pgp_get_key_rating(
  1103     PEP_SESSION session,
  1104     const char *fpr,
  1105     PEP_comm_type *comm_type
  1106     )
  1107 {
  1108     pEpSession *_session = (pEpSession *) session;
  1109     PEP_STATUS status = PEP_STATUS_OK;
  1110     gpgme_error_t gpgme_error;
  1111     gpgme_key_t key;
  1112 
  1113     assert(session);
  1114     assert(fpr);
  1115     assert(comm_type);
  1116 
  1117     *comm_type = PEP_ct_unknown;
  1118 
  1119     gpgme_error = _session->gpg.gpgme_op_keylist_start(_session->ctx, fpr, 0);
  1120     switch (gpgme_error) {
  1121     case GPG_ERR_NO_ERROR:
  1122         break;
  1123     case GPG_ERR_INV_VALUE:
  1124         assert(0);
  1125         return PEP_UNKNOWN_ERROR;
  1126     default:
  1127         return PEP_GET_KEY_FAILED;
  1128     };
  1129 
  1130     gpgme_error = _session->gpg.gpgme_op_keylist_next(_session->ctx, &key);
  1131     assert(gpgme_error != GPG_ERR_INV_VALUE);
  1132 
  1133     if (key == NULL) {
  1134         _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1135         return PEP_KEY_NOT_FOUND;
  1136     }
  1137 
  1138     switch (key->protocol) {
  1139     case GPGME_PROTOCOL_OpenPGP:
  1140     case GPGME_PROTOCOL_DEFAULT:
  1141         *comm_type = PEP_ct_OpenPGP_unconfirmed;
  1142         break;
  1143     case GPGME_PROTOCOL_CMS:
  1144         *comm_type = PEP_ct_CMS_unconfirmed;
  1145         break;
  1146     default:
  1147         *comm_type = PEP_ct_unknown;
  1148         _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1149         return PEP_STATUS_OK;
  1150     }
  1151 
  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         for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
  1159             if (sk->length < 1024)
  1160                 *comm_type = PEP_ct_key_too_short;
  1161             else if (
  1162                 (
  1163                 (sk->pubkey_algo == GPGME_PK_RSA)
  1164                 || (sk->pubkey_algo == GPGME_PK_RSA_E)
  1165                 || (sk->pubkey_algo == GPGME_PK_RSA_S)
  1166                 )
  1167                 && sk->length == 1024
  1168                 )
  1169                 *comm_type = PEP_ct_OpenPGP_1024_RSA_unconfirmed;
  1170 
  1171             if (sk->invalid) {
  1172                 *comm_type = PEP_ct_key_b0rken;
  1173                 break;
  1174             }
  1175             if (sk->expired) {
  1176                 *comm_type = PEP_ct_key_expired;
  1177                 break;
  1178             }
  1179             if (sk->revoked) {
  1180                 *comm_type = PEP_ct_key_revoked;
  1181                 break;
  1182             }
  1183         }
  1184         break;
  1185     case GPG_ERR_ENOMEM:
  1186         _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1187         *comm_type = PEP_ct_unknown;
  1188         return PEP_OUT_OF_MEMORY;
  1189     default:
  1190         // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
  1191         // reading first key
  1192 #ifndef NDEBUG
  1193         fprintf(stderr, "warning: unknown result 0x%x of"
  1194             " gpgme_op_keylist_next()\n", gpgme_error);
  1195 #endif
  1196         gpgme_error = GPG_ERR_EOF;
  1197         break;
  1198     };
  1199 
  1200     _session->gpg.gpgme_op_keylist_end(_session->ctx);
  1201 
  1202     return status;
  1203 }