merged and updated pgp_netpgp's pgp_key_expired and pgp_key_revoke
authorEdouard Tisserant
Sat, 25 Apr 2015 01:23:46 +0200
changeset 226a2079f2f7a8c
parent 225 ed16ea1bece7
parent 224 442f6dbe1d87
child 227 9321f8fb77c2
merged and updated pgp_netpgp's pgp_key_expired and pgp_key_revoke
src/pgp_netpgp.c
src/pgp_netpgp.h
     1.1 --- a/src/Makefile	Sat Apr 25 01:15:24 2015 +0200
     1.2 +++ b/src/Makefile	Sat Apr 25 01:23:46 2015 +0200
     1.3 @@ -85,7 +85,7 @@
     1.4  install: $(TARGET)
     1.5  	cp $< $(PREFIX)/lib/
     1.6  	mkdir -p $(PREFIX)/include/pEp
     1.7 -	cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h $(PREFIX)/include/pEp/
     1.8 +	cp pEpEngine.h keymanagement.h message_api.h dynamic_api.h stringlist.h timestamp.h identity_list.h bloblist.h stringpair.h message.h mime.h $(PREFIX)/include/pEp/
     1.9  
    1.10  uninstall:
    1.11  	rm -f $(PREFIX)/lib/$(TARGET)
     2.1 --- a/src/cryptotech.c	Sat Apr 25 01:15:24 2015 +0200
     2.2 +++ b/src/cryptotech.c	Sat Apr 25 01:23:46 2015 +0200
     2.3 @@ -40,6 +40,7 @@
     2.4          cryptotech[PEP_crypt_OpenPGP].send_key = pgp_send_key;
     2.5          cryptotech[PEP_crypt_OpenPGP].renew_key = pgp_renew_key;
     2.6          cryptotech[PEP_crypt_OpenPGP].revoke_key = pgp_revoke_key;
     2.7 +        cryptotech[PEP_crypt_OpenPGP].key_expired = pgp_key_expired;
     2.8      }
     2.9  
    2.10      session->cryptotech = cryptotech;
     3.1 --- a/src/cryptotech.h	Sat Apr 25 01:15:24 2015 +0200
     3.2 +++ b/src/cryptotech.h	Sat Apr 25 01:23:46 2015 +0200
     3.3 @@ -54,10 +54,14 @@
     3.4  
     3.5  typedef PEP_STATUS (*send_key_t)(PEP_SESSION session, const char *pattern);
     3.6  
     3.7 -typedef PEP_STATUS (*renew_key_t)(PEP_SESSION session, const char *key_id,
     3.8 +typedef PEP_STATUS (*renew_key_t)(PEP_SESSION session, const char *fpr,
     3.9          const timestamp *ts);
    3.10  
    3.11 -typedef PEP_STATUS (*revoke_key_t)(PEP_SESSION session, const char *key_id);
    3.12 +typedef PEP_STATUS (*revoke_key_t)(PEP_SESSION session, const char *fpr,
    3.13 +        const char *reason);
    3.14 +
    3.15 +typedef PEP_STATUS (*key_expired_t)(PEP_SESSION session, const char *fpr,
    3.16 +        bool *expired);
    3.17  
    3.18  typedef struct _PEP_cryptotech_t {
    3.19      uint8_t id;
    3.20 @@ -77,6 +81,7 @@
    3.21      send_key_t send_key;
    3.22      renew_key_t renew_key;
    3.23      revoke_key_t revoke_key;
    3.24 +    key_expired_t key_expired;
    3.25  } PEP_cryptotech_t;
    3.26  
    3.27  typedef uint64_t cryptotech_mask;
     4.1 --- a/src/keymanagement.c	Sat Apr 25 01:15:24 2015 +0200
     4.2 +++ b/src/keymanagement.c	Sat Apr 25 01:23:46 2015 +0200
     4.3 @@ -5,8 +5,7 @@
     4.4  #include <stdlib.h>
     4.5  #include <assert.h>
     4.6  
     4.7 -#define _EXPORT_PEP_ENGINE_DLL
     4.8 -#include "pEpEngine.h"
     4.9 +#include "pEp_internal.h"
    4.10  #include "keymanagement.h"
    4.11  
    4.12  #ifndef MIN
    4.13 @@ -17,6 +16,8 @@
    4.14  #define EMPTY(STR) ((STR == NULL) || (STR)[0] == 0)
    4.15  #endif
    4.16  
    4.17 +#define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
    4.18 +
    4.19  DYNAMIC_API PEP_STATUS update_identity(
    4.20          PEP_SESSION session, pEp_identity * identity
    4.21      )
    4.22 @@ -202,7 +203,7 @@
    4.23  
    4.24      pEp_identity *_identity;
    4.25  
    4.26 -    log_event(session, "myself", "debug", identity->address, NULL);
    4.27 +    DEBUG_LOG("myself", "debug", identity->address);
    4.28      status = get_identity(session, identity->address, &_identity);
    4.29      assert(status != PEP_OUT_OF_MEMORY);
    4.30      if (status == PEP_OUT_OF_MEMORY)
    4.31 @@ -214,13 +215,13 @@
    4.32          return PEP_OUT_OF_MEMORY;
    4.33  
    4.34      if (keylist == NULL || keylist->value == NULL) {
    4.35 -        log_event(session, "generating key pair", "debug", identity->address, NULL);
    4.36 +        DEBUG_LOG("generating key pair", "debug", identity->address);
    4.37          status = generate_keypair(session, identity);
    4.38          assert(status != PEP_OUT_OF_MEMORY);
    4.39          if (status != PEP_STATUS_OK) {
    4.40              char buf[11];
    4.41              snprintf(buf, 11, "%d", status);
    4.42 -            log_event(session, "generating key pair failed", "debug", buf, NULL);
    4.43 +            DEBUG_LOG("generating key pair failed", "debug", buf);
    4.44              return status;
    4.45          }
    4.46  
    4.47 @@ -231,6 +232,17 @@
    4.48  
    4.49          assert(keylist);
    4.50      }
    4.51 +    else {
    4.52 +        bool expired;
    4.53 +        status = key_expired(session, keylist->value, &expired);
    4.54 +        assert(status == PEP_STATUS_OK);
    4.55 +
    4.56 +        if (status == PEP_STATUS_OK && expired) {
    4.57 +            timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
    4.58 +            renew_key(session, keylist->value, ts);
    4.59 +            free_timestamp(ts);
    4.60 +        }
    4.61 +    }
    4.62  
    4.63      if (identity->fpr)
    4.64          free(identity->fpr);
    4.65 @@ -267,7 +279,7 @@
    4.66  
    4.67      while ((identity = retrieve_next_identity(management))) {
    4.68          assert(identity->address);
    4.69 -        log_event(session, "do_keymanagement", "debug", identity->address, NULL);
    4.70 +        DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
    4.71          if (identity->me) {
    4.72              status = myself(session, identity);
    4.73              assert(status != PEP_OUT_OF_MEMORY);
    4.74 @@ -284,3 +296,18 @@
    4.75      return PEP_STATUS_OK;
    4.76  }
    4.77  
    4.78 +DYNAMIC_API PEP_STATUS key_compromized(PEP_SESSION session, const char *fpr)
    4.79 +{
    4.80 +    PEP_STATUS status = PEP_STATUS_OK;
    4.81 +
    4.82 +    assert(session);
    4.83 +    assert(fpr);
    4.84 +
    4.85 +    if (!(session && fpr))
    4.86 +        return PEP_ILLEGAL_VALUE;
    4.87 +
    4.88 +    status = revoke_key(session, fpr, NULL);
    4.89 +
    4.90 +    return status;
    4.91 +}
    4.92 +
     5.1 --- a/src/keymanagement.h	Sat Apr 25 01:15:24 2015 +0200
     5.2 +++ b/src/keymanagement.h	Sat Apr 25 01:23:46 2015 +0200
     5.3 @@ -1,5 +1,7 @@
     5.4  #pragma once
     5.5  
     5.6 +#include "pEpEngine.h"
     5.7 +
     5.8  #ifdef __cplusplus
     5.9  extern "C" {
    5.10  #endif
    5.11 @@ -84,6 +86,16 @@
    5.12          void *management
    5.13      );
    5.14  
    5.15 +
    5.16 +// key_compromized() - mark key as being compromized
    5.17 +//
    5.18 +//  parameters:
    5.19 +//      session (in)        session to use
    5.20 +//      fpr (in)            key which was compromized
    5.21 +
    5.22 +DYNAMIC_API PEP_STATUS key_compromized(PEP_SESSION session, const char *fpr);
    5.23 +
    5.24 +
    5.25  #ifdef __cplusplus
    5.26  }
    5.27  #endif
     6.1 --- a/src/message_api.c	Sat Apr 25 01:15:24 2015 +0200
     6.2 +++ b/src/message_api.c	Sat Apr 25 01:23:46 2015 +0200
     6.3 @@ -2,6 +2,7 @@
     6.4  #include "message_api.h"
     6.5  
     6.6  #include "platform.h"
     6.7 +#include "mime.h"
     6.8  
     6.9  #include <assert.h>
    6.10  #include <string.h>
     7.1 --- a/src/message_api.h	Sat Apr 25 01:15:24 2015 +0200
     7.2 +++ b/src/message_api.h	Sat Apr 25 01:23:46 2015 +0200
     7.3 @@ -3,7 +3,6 @@
     7.4  #include "pEpEngine.h"
     7.5  #include "keymanagement.h"
     7.6  #include "message.h"
     7.7 -#include "mime.h"
     7.8  
     7.9  #ifdef __cplusplus
    7.10  extern "C" {
     8.1 --- a/src/pEpEngine.c	Sat Apr 25 01:15:24 2015 +0200
     8.2 +++ b/src/pEpEngine.c	Sat Apr 25 01:23:46 2015 +0200
     8.3 @@ -3,7 +3,7 @@
     8.4  #include "cryptotech.h"
     8.5  #include "transport.h"
     8.6  
     8.7 -int init_count = -1;
     8.8 +static int init_count = -1;
     8.9  
    8.10  DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
    8.11  {
    8.12 @@ -913,7 +913,11 @@
    8.13      return session->cryptotech[PEP_crypt_OpenPGP].renew_key(session, fpr, ts);
    8.14  }
    8.15  
    8.16 -DYNAMIC_API PEP_STATUS revoke_key(PEP_SESSION session, const char *fpr)
    8.17 +DYNAMIC_API PEP_STATUS revoke_key(
    8.18 +        PEP_SESSION session,
    8.19 +        const char *fpr,
    8.20 +        const char *reason
    8.21 +    )
    8.22  {
    8.23      assert(session);
    8.24      assert(fpr);
    8.25 @@ -921,6 +925,24 @@
    8.26      if (!(session && fpr))
    8.27          return PEP_ILLEGAL_VALUE;
    8.28  
    8.29 -    return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr);
    8.30 +    return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr,
    8.31 +            reason);
    8.32  }
    8.33  
    8.34 +DYNAMIC_API PEP_STATUS key_expired(
    8.35 +        PEP_SESSION session,
    8.36 +        const char *fpr,
    8.37 +        bool *expired
    8.38 +    )
    8.39 +{
    8.40 +    assert(session);
    8.41 +    assert(fpr);
    8.42 +    assert(expired);
    8.43 +
    8.44 +    if (!(session && fpr && expired))
    8.45 +        return PEP_ILLEGAL_VALUE;
    8.46 +
    8.47 +    return session->cryptotech[PEP_crypt_OpenPGP].key_expired(session, fpr,
    8.48 +            expired);
    8.49 +}
    8.50 +
     9.1 --- a/src/pEpEngine.h	Sat Apr 25 01:15:24 2015 +0200
     9.2 +++ b/src/pEpEngine.h	Sat Apr 25 01:23:46 2015 +0200
     9.3 @@ -611,7 +611,7 @@
     9.4  //
     9.5  //  parameters:
     9.6  //      session (in)            session handle
     9.7 -//      key_id (in)             ID of key to renew as UTF-8 string
     9.8 +//      fpr (in)                ID of key to renew as UTF-8 string
     9.9  //      ts (in)                 timestamp when key should expire or NULL for
    9.10  //                              default
    9.11  
    9.12 @@ -622,13 +622,38 @@
    9.13      );
    9.14  
    9.15  
    9.16 -// revoke_key() - revoke an expired key
    9.17 +// revoke_key() - revoke a key
    9.18  //
    9.19  //  parameters:
    9.20  //      session (in)            session handle
    9.21 -//      key_id (in)             ID of key to revoke as UTF-8 string
    9.22 +//      fpr (in)                ID of key to revoke as UTF-8 string
    9.23 +//      reason (in)             text with reason for revoke as UTF-8 string
    9.24 +//                              or NULL if reason unknown
    9.25 +//
    9.26 +//  caveat:
    9.27 +//      reason text must not include empty lines
    9.28 +//      this function is meant for internal use only; better use
    9.29 +//      key_compromized() of keymanagement API
    9.30  
    9.31 -DYNAMIC_API PEP_STATUS revoke_key(PEP_SESSION session, const char *fpr);
    9.32 +DYNAMIC_API PEP_STATUS revoke_key(
    9.33 +        PEP_SESSION session,
    9.34 +        const char *fpr,
    9.35 +        const char *reason
    9.36 +    );
    9.37 +
    9.38 +
    9.39 +// key_expired() - flags if a key is already expired
    9.40 +//
    9.41 +//  parameters:
    9.42 +//      session (in)            session handle
    9.43 +//      fpr (in)                ID of key to check as UTF-8 string
    9.44 +//      expired (out)           flag if key expired
    9.45 +
    9.46 +DYNAMIC_API PEP_STATUS key_expired(
    9.47 +        PEP_SESSION session,
    9.48 +        const char *fpr,
    9.49 +        bool *expired
    9.50 +    );
    9.51  
    9.52  
    9.53  #ifdef __cplusplus
    10.1 --- a/src/pEp_internal.h	Sat Apr 25 01:15:24 2015 +0200
    10.2 +++ b/src/pEp_internal.h	Sat Apr 25 01:23:46 2015 +0200
    10.3 @@ -39,10 +39,6 @@
    10.4  #include <assert.h>
    10.5  #include <stdio.h>
    10.6  
    10.7 -#ifndef NDEBUG
    10.8 -#include <stdio.h>
    10.9 -#endif
   10.10 -
   10.11  #include "sqlite3.h"
   10.12  
   10.13  #define _EXPORT_PEP_ENGINE_DLL
   10.14 @@ -93,3 +89,10 @@
   10.15  PEP_STATUS init_transport_system(PEP_SESSION session, bool in_first);
   10.16  void release_transport_system(PEP_SESSION session, bool out_last);
   10.17  
   10.18 +#ifdef NDEBUG
   10.19 +#define DEBUG_LOG(TITLE, ENTITY, DESC)
   10.20 +#else
   10.21 +#define DEBUG_LOG(TITLE, ENTITY, DESC) \
   10.22 +    log_event(session, (TITLE), (ENTITY), (DESC), "debug");
   10.23 +#endif
   10.24 +
    11.1 --- a/src/pgp_gpg.c	Sat Apr 25 01:15:24 2015 +0200
    11.2 +++ b/src/pgp_gpg.c	Sat Apr 25 01:23:46 2015 +0200
    11.3 @@ -1,3 +1,4 @@
    11.4 +#include "platform.h"
    11.5  #include "pEp_internal.h"
    11.6  #include "pgp_gpg.h"
    11.7  
    11.8 @@ -164,6 +165,11 @@
    11.9              "gpgme_data_new_from_mem");
   11.10          assert(gpg.gpgme_data_new_from_mem);
   11.11  
   11.12 +        gpg.gpgme_data_new_from_cbs
   11.13 +            = (gpgme_data_new_from_cbs_t) (intptr_t) dlsym(gpgme,
   11.14 +            "gpgme_data_new_from_cbs");
   11.15 +        assert(gpg.gpgme_data_new_from_cbs);
   11.16 +
   11.17          gpg.gpgme_data_release
   11.18              = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
   11.19              "gpgme_data_release");
   11.20 @@ -282,6 +288,14 @@
   11.21              dlsym(gpgme, "gpgme_key_unref");
   11.22          assert(gpg.gpgme_key_unref);
   11.23  
   11.24 +        gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
   11.25 +            dlsym(gpgme, "gpgme_op_edit");
   11.26 +        assert(gpg.gpgme_op_edit);
   11.27 +
   11.28 +        gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
   11.29 +            dlsym(gpgme, "gpgme_io_write");
   11.30 +        assert(gpg.gpgme_io_write);
   11.31 +
   11.32          gpg.version = gpg.gpgme_check(NULL);
   11.33          
   11.34          if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
   11.35 @@ -1323,7 +1337,7 @@
   11.36  }
   11.37  
   11.38  typedef struct _renew_state {
   11.39 -    enum state_t {
   11.40 +    enum {
   11.41          renew_command = 0,
   11.42          renew_date,
   11.43          renew_secret_key,
   11.44 @@ -1354,7 +1368,7 @@
   11.45                      handle->state = renew_error;
   11.46                      return GPG_ERR_GENERAL;
   11.47                  }
   11.48 -                write(fd, "expire\n", 7);
   11.49 +                gpg.gpgme_io_write(fd, "expire\n", 7);
   11.50                  handle->state = renew_date;
   11.51              }
   11.52              break;
   11.53 @@ -1366,7 +1380,7 @@
   11.54                      handle->state = renew_error;
   11.55                      return GPG_ERR_GENERAL;
   11.56                  }
   11.57 -                write(fd, handle->date_ref, 11);
   11.58 +                gpg.gpgme_io_write(fd, handle->date_ref, 11);
   11.59                  handle->state = renew_secret_key;
   11.60              }
   11.61              break;
   11.62 @@ -1378,7 +1392,7 @@
   11.63                      handle->state = renew_error;
   11.64                      return GPG_ERR_GENERAL;
   11.65                  }
   11.66 -                write(fd, "key 1\n", 6);
   11.67 +                gpg.gpgme_io_write(fd, "key 1\n", 6);
   11.68                  handle->state = renew_command2;
   11.69              }
   11.70              break;
   11.71 @@ -1390,7 +1404,7 @@
   11.72                      handle->state = renew_error;
   11.73                      return GPG_ERR_GENERAL;
   11.74                  }
   11.75 -                write(fd, "expire\n", 7);
   11.76 +                gpg.gpgme_io_write(fd, "expire\n", 7);
   11.77                  handle->state = renew_date2;
   11.78              }
   11.79              break;
   11.80 @@ -1402,7 +1416,7 @@
   11.81                      handle->state = renew_error;
   11.82                      return GPG_ERR_GENERAL;
   11.83                  }
   11.84 -                write(fd, handle->date_ref, 11);
   11.85 +                gpg.gpgme_io_write(fd, handle->date_ref, 11);
   11.86                  handle->state = renew_quit;
   11.87              }
   11.88              break;
   11.89 @@ -1414,7 +1428,7 @@
   11.90                      handle->state = renew_error;
   11.91                      return GPG_ERR_GENERAL;
   11.92                  }
   11.93 -                write(fd, "quit\n", 5);
   11.94 +                gpg.gpgme_io_write(fd, "quit\n", 5);
   11.95                  handle->state = renew_save;
   11.96              }
   11.97              break;
   11.98 @@ -1426,7 +1440,7 @@
   11.99                      handle->state = renew_error;
  11.100                      return GPG_ERR_GENERAL;
  11.101                  }
  11.102 -                write(fd, "Y\n", 2);
  11.103 +                gpg.gpgme_io_write(fd, "Y\n", 2);
  11.104                  handle->state = renew_exit;
  11.105              }
  11.106              break;
  11.107 @@ -1478,9 +1492,9 @@
  11.108      struct gpgme_data_cbs data_cbs;
  11.109      memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  11.110      data_cbs.write = _nullwriter;
  11.111 -    gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  11.112 +    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  11.113  
  11.114 -    gpgme_error = gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  11.115 +    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, renew_fsm, &handle,
  11.116              output);
  11.117      assert(gpgme_error == GPG_ERR_NO_ERROR);
  11.118  
  11.119 @@ -1490,18 +1504,211 @@
  11.120      return PEP_STATUS_OK;
  11.121  }
  11.122  
  11.123 -PEP_STATUS pgp_revoke_key(PEP_SESSION session, const char *fpr)
  11.124 +typedef struct _revoke_state {
  11.125 +    enum {
  11.126 +        revoke_command = 0,
  11.127 +        revoke_approve,
  11.128 +        revoke_reason_code,
  11.129 +        revoke_reason_text,
  11.130 +        revoke_reason_ok,
  11.131 +        revoke_quit,
  11.132 +        revoke_save,
  11.133 +        revoke_exit,
  11.134 +        revoke_error = -1
  11.135 +    } state;
  11.136 +    const char *reason_ref;
  11.137 +} revoke_state;
  11.138 +
  11.139 +static bool isemptystring(const char *str)
  11.140 +{
  11.141 +    if (str == NULL)
  11.142 +        return true;
  11.143 +
  11.144 +    for (; str; str++) {
  11.145 +        if (*str != ' ' && *str != '\t' && *str != '\n')
  11.146 +            return false;
  11.147 +    }
  11.148 +
  11.149 +    return true;
  11.150 +}
  11.151 +
  11.152 +static gpgme_error_t revoke_fsm(
  11.153 +        void *_handle,
  11.154 +        gpgme_status_code_t statuscode,
  11.155 +        const char *args,
  11.156 +        int fd
  11.157 +    )
  11.158 +{
  11.159 +    revoke_state *handle = _handle;
  11.160 +
  11.161 +    switch (handle->state) {
  11.162 +        case revoke_command:
  11.163 +            if (statuscode == GPGME_STATUS_GET_LINE) {
  11.164 +                assert(strcmp(args, "keyedit.prompt") == 0);
  11.165 +                if (strcmp(args, "keyedit.prompt")) {
  11.166 +                    handle->state = revoke_error;
  11.167 +                    return GPG_ERR_GENERAL;
  11.168 +                }
  11.169 +                gpg.gpgme_io_write(fd, "revkey\n", 7);
  11.170 +                handle->state = revoke_approve;
  11.171 +            }
  11.172 +            break;
  11.173 +
  11.174 +        case revoke_approve:
  11.175 +            if (statuscode == GPGME_STATUS_GET_BOOL) {
  11.176 +                assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
  11.177 +                if (strcmp(args, "keyedit.revoke.subkey.okay")) {
  11.178 +                    handle->state = revoke_error;
  11.179 +                    return GPG_ERR_GENERAL;
  11.180 +                }
  11.181 +                gpg.gpgme_io_write(fd, "Y\n", 2);
  11.182 +                handle->state = revoke_reason_code;
  11.183 +            }
  11.184 +            break;
  11.185 +
  11.186 +        case revoke_reason_code:
  11.187 +            if (statuscode == GPGME_STATUS_GET_LINE) {
  11.188 +                assert(strcmp(args, "ask_revocation_reason.code") == 0);
  11.189 +                if (strcmp(args, "ask_revocation_reason.code")) {
  11.190 +                    handle->state = revoke_error;
  11.191 +                    return GPG_ERR_GENERAL;
  11.192 +                }
  11.193 +                gpg.gpgme_io_write(fd, "1\n", 2);
  11.194 +                handle->state = revoke_reason_text;
  11.195 +            }
  11.196 +            break;
  11.197 +
  11.198 +        case revoke_reason_text:
  11.199 +            if (statuscode == GPGME_STATUS_GET_LINE) {
  11.200 +                assert(strcmp(args, "ask_revocation_reason.text") == 0);
  11.201 +                if (strcmp(args, "ask_revocation_reason.text")) {
  11.202 +                    handle->state = revoke_error;
  11.203 +                    return GPG_ERR_GENERAL;
  11.204 +                }
  11.205 +                // BUG: issues when reason given
  11.206 +                // Assertion failed: (gpg->cmd.code), function command_handler,
  11.207 +                // file engine-gpg.c, line 662.
  11.208 +                //
  11.209 +                // if (isemptystring(handle->reason_ref)) {
  11.210 +                    gpg.gpgme_io_write(fd, "\n", 1);
  11.211 +                // }
  11.212 +                // else {
  11.213 +                //     size_t len = strlen(handle->reason_ref);
  11.214 +                //     gpg.gpgme_io_write(fd, handle->reason_ref, len);
  11.215 +                //     if (handle->reason_ref[len - 1] == '\n')
  11.216 +                //         gpg.gpgme_io_write(fd, "\n", 1);
  11.217 +                //     else
  11.218 +                //         gpg.gpgme_io_write(fd, "\n\n", 2);
  11.219 +                // }
  11.220 +                handle->state = revoke_reason_ok;
  11.221 +            }
  11.222 +            break;
  11.223 +
  11.224 +        case revoke_reason_ok:
  11.225 +            if (statuscode == GPGME_STATUS_GET_BOOL) {
  11.226 +                assert(strcmp(args, "ask_revocation_reason.okay") == 0);
  11.227 +                if (strcmp(args, "ask_revocation_reason.okay")) {
  11.228 +                    handle->state = revoke_error;
  11.229 +                    return GPG_ERR_GENERAL;
  11.230 +                }
  11.231 +                gpg.gpgme_io_write(fd, "Y\n", 2);
  11.232 +                handle->state = revoke_quit;
  11.233 +            }
  11.234 +            break;
  11.235 +
  11.236 +        case revoke_quit:
  11.237 +            if (statuscode == GPGME_STATUS_GET_LINE) {
  11.238 +                assert(strcmp(args, "keyedit.prompt") == 0);
  11.239 +                if (strcmp(args, "keyedit.prompt")) {
  11.240 +                    handle->state = revoke_error;
  11.241 +                    return GPG_ERR_GENERAL;
  11.242 +                }
  11.243 +                gpg.gpgme_io_write(fd, "quit\n", 5);
  11.244 +                handle->state = revoke_save;
  11.245 +            }
  11.246 +            break;
  11.247 +
  11.248 +        case revoke_save:
  11.249 +            if (statuscode == GPGME_STATUS_GET_BOOL) {
  11.250 +                assert(strcmp(args, "keyedit.save.okay") == 0);
  11.251 +                if (strcmp(args, "keyedit.save.okay")) {
  11.252 +                    handle->state = revoke_error;
  11.253 +                    return GPG_ERR_GENERAL;
  11.254 +                }
  11.255 +                gpg.gpgme_io_write(fd, "Y\n", 2);
  11.256 +                handle->state = revoke_exit;
  11.257 +            }
  11.258 +            break;
  11.259 +
  11.260 +        case revoke_exit:
  11.261 +            break;
  11.262 +
  11.263 +        case revoke_error:
  11.264 +            return GPG_ERR_GENERAL;
  11.265 +    }
  11.266 +
  11.267 +    return GPG_ERR_NO_ERROR;
  11.268 +}
  11.269 +
  11.270 +PEP_STATUS pgp_revoke_key(
  11.271 +        PEP_SESSION session,
  11.272 +        const char *fpr,
  11.273 +        const char *reason
  11.274 +    )
  11.275  {
  11.276      PEP_STATUS status = PEP_STATUS_OK;
  11.277 +    gpgme_error_t gpgme_error;
  11.278      gpgme_key_t key;
  11.279 -    
  11.280 +    gpgme_data_t output;
  11.281 +    revoke_state handle;
  11.282 +
  11.283      assert(session);
  11.284      assert(fpr);
  11.285  
  11.286 +    memset(&handle, 0, sizeof(revoke_state));
  11.287 +    handle.reason_ref = reason;
  11.288 +
  11.289      status = find_single_key(session, fpr, &key);
  11.290      if (status != PEP_STATUS_OK)
  11.291          return status;
  11.292  
  11.293 +    struct gpgme_data_cbs data_cbs;
  11.294 +    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
  11.295 +    data_cbs.write = _nullwriter;
  11.296 +    gpg.gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
  11.297 +
  11.298 +    gpgme_error = gpg.gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
  11.299 +            output);
  11.300 +    assert(gpgme_error == GPG_ERR_NO_ERROR);
  11.301 +
  11.302 +    gpg.gpgme_data_release(output);
  11.303 +    gpg.gpgme_key_unref(key);
  11.304 +
  11.305      return PEP_STATUS_OK;
  11.306  }
  11.307  
  11.308 +PEP_STATUS pgp_key_expired(
  11.309 +        PEP_SESSION session,
  11.310 +        const char *fpr,
  11.311 +        bool *expired
  11.312 +    )
  11.313 +{
  11.314 +    PEP_STATUS status = PEP_STATUS_OK;
  11.315 +    gpgme_key_t key;
  11.316 +
  11.317 +    assert(session);
  11.318 +    assert(fpr);
  11.319 +    assert(expired);
  11.320 +
  11.321 +    *expired = false;
  11.322 +
  11.323 +    status = find_single_key(session, fpr, &key);
  11.324 +    assert(status != PEP_OUT_OF_MEMORY);
  11.325 +    if (status != PEP_STATUS_OK)
  11.326 +        return status;
  11.327 +
  11.328 +    *expired = key->subkeys->expired;
  11.329 +    gpg.gpgme_key_unref(key);
  11.330 +    return PEP_STATUS_OK;
  11.331 +}
  11.332 +
    12.1 --- a/src/pgp_gpg.h	Sat Apr 25 01:15:24 2015 +0200
    12.2 +++ b/src/pgp_gpg.h	Sat Apr 25 01:23:46 2015 +0200
    12.3 @@ -52,5 +52,15 @@
    12.4          const timestamp *ts
    12.5      );
    12.6  
    12.7 -PEP_STATUS pgp_revoke_key(PEP_SESSION session, const char *fpr);
    12.8 +PEP_STATUS pgp_revoke_key(
    12.9 +        PEP_SESSION session,
   12.10 +        const char *fpr,
   12.11 +        const char *reason
   12.12 +    );
   12.13  
   12.14 +PEP_STATUS pgp_key_expired(
   12.15 +        PEP_SESSION session,
   12.16 +        const char *fpr,
   12.17 +        bool *expired
   12.18 +    );
   12.19 +
    13.1 --- a/src/pgp_gpg_internal.h	Sat Apr 25 01:15:24 2015 +0200
    13.2 +++ b/src/pgp_gpg_internal.h	Sat Apr 25 01:23:46 2015 +0200
    13.3 @@ -18,6 +18,8 @@
    13.4  typedef gpgme_error_t(*gpgme_data_new_t)(gpgme_data_t *DH);
    13.5  typedef gpgme_error_t(*gpgme_data_new_from_mem_t)(gpgme_data_t *DH,
    13.6      const char *BUFFER, size_t SIZE, int COPY);
    13.7 +typedef gpgme_error_t (*gpgme_data_new_from_cbs_t)(gpgme_data_t *DH,
    13.8 +        gpgme_data_cbs_t CBS, void *HANDLE);
    13.9  typedef void(*gpgme_data_release_t)(gpgme_data_t DH);
   13.10  typedef gpgme_data_type_t(*gpgme_data_identify_t)(gpgme_data_t DH);
   13.11  typedef size_t(*gpgme_data_seek_t)(gpgme_data_t DH, size_t OFFSET,
   13.12 @@ -66,6 +68,10 @@
   13.13      gpgme_key_t *KEYS);
   13.14  typedef void(*gpgme_key_ref_t)(gpgme_key_t KEY);
   13.15  typedef void(*gpgme_key_unref_t)(gpgme_key_t KEY);
   13.16 +typedef gpgme_error_t (*gpgme_op_edit_t)(gpgme_ctx_t CTX, gpgme_key_t KEY,
   13.17 +        gpgme_edit_cb_t FNC, void *HANDLE, gpgme_data_t OUT);
   13.18 +typedef gpgme_ssize_t (*gpgme_io_write_t)(int fd, const void *buffer,
   13.19 +        size_t count);
   13.20  
   13.21  struct gpg_s {
   13.22      const char * version;
   13.23 @@ -78,6 +84,7 @@
   13.24  
   13.25      gpgme_data_new_t gpgme_data_new;
   13.26      gpgme_data_new_from_mem_t gpgme_data_new_from_mem;
   13.27 +    gpgme_data_new_from_cbs_t gpgme_data_new_from_cbs;
   13.28      gpgme_data_release_t gpgme_data_release;
   13.29      gpgme_data_identify_t gpgme_data_identify;
   13.30      gpgme_data_seek_t gpgme_data_seek;
   13.31 @@ -106,4 +113,6 @@
   13.32      gpgme_op_import_keys_t gpgme_op_import_keys;
   13.33      gpgme_key_ref_t gpgme_key_ref;
   13.34      gpgme_key_unref_t gpgme_key_unref;
   13.35 +    gpgme_op_edit_t gpgme_op_edit;
   13.36 +    gpgme_io_write_t gpgme_io_write;
   13.37  };
    14.1 --- a/src/pgp_netpgp.c	Sat Apr 25 01:15:24 2015 +0200
    14.2 +++ b/src/pgp_netpgp.c	Sat Apr 25 01:23:46 2015 +0200
    14.3 @@ -807,7 +807,11 @@
    14.4      return PEP_STATUS_OK;
    14.5  }
    14.6  
    14.7 -PEP_STATUS pgp_revoke_key(PEP_SESSION session, const char *fpr)
    14.8 +PEP_STATUS pgp_revoke_key(
    14.9 +        PEP_SESSION session,
   14.10 +        const char *fpr,
   14.11 +        const char *reason
   14.12 +    )
   14.13  {
   14.14      PEP_STATUS status = PEP_STATUS_OK;
   14.15      
   14.16 @@ -819,3 +823,23 @@
   14.17      return PEP_STATUS_OK;
   14.18  }
   14.19  
   14.20 +PEP_STATUS pgp_key_expired(
   14.21 +        PEP_SESSION session,
   14.22 +        const char *fpr,
   14.23 +        bool *expired
   14.24 +    )
   14.25 +{
   14.26 +    PEP_STATUS status = PEP_STATUS_OK;
   14.27 +
   14.28 +    assert(session);
   14.29 +    assert(fpr);
   14.30 +    assert(expired);
   14.31 +
   14.32 +    *expired = false;
   14.33 +
   14.34 +    if (status != PEP_STATUS_OK)
   14.35 +        return status;
   14.36 +
   14.37 +    return PEP_STATUS_OK;
   14.38 +}
   14.39 +
    15.1 --- a/src/pgp_netpgp.h	Sat Apr 25 01:15:24 2015 +0200
    15.2 +++ b/src/pgp_netpgp.h	Sat Apr 25 01:23:46 2015 +0200
    15.3 @@ -44,7 +44,6 @@
    15.4          size_t size);
    15.5  
    15.6  PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern);
    15.7 -
    15.8  PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern);
    15.9  
   15.10  PEP_STATUS pgp_renew_key(
   15.11 @@ -53,4 +52,15 @@
   15.12          const timestamp *ts
   15.13      );
   15.14  
   15.15 -PEP_STATUS pgp_revoke_key(PEP_SESSION session, const char *fpr);
   15.16 +PEP_STATUS pgp_revoke_key(
   15.17 +        PEP_SESSION session,
   15.18 +        const char *fpr,
   15.19 +        const char *reason
   15.20 +    );
   15.21 +
   15.22 +PEP_STATUS pgp_key_expired(
   15.23 +        PEP_SESSION session,
   15.24 +        const char *fpr,
   15.25 +        bool *expired
   15.26 +    );
   15.27 +
    16.1 --- a/src/platform_windows.h	Sat Apr 25 01:15:24 2015 +0200
    16.2 +++ b/src/platform_windows.h	Sat Apr 25 01:23:46 2015 +0200
    16.3 @@ -6,11 +6,13 @@
    16.4  
    16.5  #include <string.h>
    16.6  #include <io.h>
    16.7 +#include <basetsd.h>
    16.8  
    16.9  #ifdef __cplusplus
   16.10  extern "C" {
   16.11  #endif
   16.12  
   16.13 +#define ssize_t SSIZE_T
   16.14  #define RTLD_LAZY 1
   16.15  #define mode_t int
   16.16  
    17.1 --- a/test/keyedit_test.cc	Sat Apr 25 01:15:24 2015 +0200
    17.2 +++ b/test/keyedit_test.cc	Sat Apr 25 01:23:46 2015 +0200
    17.3 @@ -22,7 +22,7 @@
    17.4  
    17.5      // generate test key
    17.6  
    17.7 -    cout << "\ngenerating key for expire test\n";
    17.8 +    cout << "\ngenerating key for keyedit test\n";
    17.9      pEp_identity *identity = new_identity(
   17.10              "expire@dingens.org",
   17.11              NULL,
   17.12 @@ -52,6 +52,13 @@
   17.13  
   17.14      cout << "key renewed.\n";
   17.15  
   17.16 +    cout << "key will be revoked\n";
   17.17 +    PEP_STATUS status3 = revoke_key(session, key.c_str(), "revoke test");
   17.18 +    cout << "revoke_key() exited with " << status3 << "\n";
   17.19 +    assert(status3 == PEP_STATUS_OK);
   17.20 +    
   17.21 +    cout << "key revoked.\n";
   17.22 +
   17.23      cout << "deleting key pair " << key.c_str() << "\n";
   17.24      PEP_STATUS delete_status = delete_keypair(session, key.c_str());
   17.25      cout << "delete_keypair() exits with " << delete_status << "\n";
    18.1 --- a/test/message_api_test.cc	Sat Apr 25 01:15:24 2015 +0200
    18.2 +++ b/test/message_api_test.cc	Sat Apr 25 01:23:46 2015 +0200
    18.3 @@ -2,6 +2,7 @@
    18.4  #include <iostream>
    18.5  #include <fstream>
    18.6  #include <assert.h>
    18.7 +#include "mime.h"
    18.8  #include "message_api.h"
    18.9  
   18.10  using namespace std;