revoke_key() fixed
authorVolker Birk <vb@pep-project.org>
Tue, 21 Apr 2015 08:37:01 +0200
changeset 211a022e853f81e
parent 205 69abe9ef3be2
child 212 6207061ddd14
revoke_key() fixed
src/cryptotech.h
src/pEpEngine.c
src/pEpEngine.h
src/pgp_gpg.c
src/pgp_gpg.h
test/keyedit_test.cc
     1.1 --- a/src/cryptotech.h	Mon Apr 20 21:03:13 2015 +0200
     1.2 +++ b/src/cryptotech.h	Tue Apr 21 08:37:01 2015 +0200
     1.3 @@ -57,7 +57,8 @@
     1.4  typedef PEP_STATUS (*renew_key_t)(PEP_SESSION session, const char *key_id,
     1.5          const timestamp *ts);
     1.6  
     1.7 -typedef PEP_STATUS (*revoke_key_t)(PEP_SESSION session, const char *key_id);
     1.8 +typedef PEP_STATUS (*revoke_key_t)(PEP_SESSION session, const char *key_id,
     1.9 +        const char *reason);
    1.10  
    1.11  typedef struct _PEP_cryptotech_t {
    1.12      uint8_t id;
     2.1 --- a/src/pEpEngine.c	Mon Apr 20 21:03:13 2015 +0200
     2.2 +++ b/src/pEpEngine.c	Tue Apr 21 08:37:01 2015 +0200
     2.3 @@ -913,7 +913,11 @@
     2.4      return session->cryptotech[PEP_crypt_OpenPGP].renew_key(session, fpr, ts);
     2.5  }
     2.6  
     2.7 -DYNAMIC_API PEP_STATUS revoke_key(PEP_SESSION session, const char *fpr)
     2.8 +DYNAMIC_API PEP_STATUS revoke_key(
     2.9 +        PEP_SESSION session,
    2.10 +        const char *fpr,
    2.11 +        const char *reason
    2.12 +    )
    2.13  {
    2.14      assert(session);
    2.15      assert(fpr);
    2.16 @@ -921,6 +925,6 @@
    2.17      if (!(session && fpr))
    2.18          return PEP_ILLEGAL_VALUE;
    2.19  
    2.20 -    return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr);
    2.21 +    return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr, reason);
    2.22  }
    2.23  
     3.1 --- a/src/pEpEngine.h	Mon Apr 20 21:03:13 2015 +0200
     3.2 +++ b/src/pEpEngine.h	Tue Apr 21 08:37:01 2015 +0200
     3.3 @@ -627,8 +627,17 @@
     3.4  //  parameters:
     3.5  //      session (in)            session handle
     3.6  //      key_id (in)             ID of key to revoke as UTF-8 string
     3.7 +//      reason (in)             text with reason for revoke as UTF-8 string
     3.8 +//                              or NULL if reason unknown
     3.9 +//
    3.10 +//  caveat:
    3.11 +//      reason text must not include empty lines
    3.12  
    3.13 -DYNAMIC_API PEP_STATUS revoke_key(PEP_SESSION session, const char *fpr);
    3.14 +DYNAMIC_API PEP_STATUS revoke_key(
    3.15 +        PEP_SESSION session,
    3.16 +        const char *fpr,
    3.17 +        const char *reason
    3.18 +    );
    3.19  
    3.20  
    3.21  #ifdef __cplusplus
     4.1 --- a/src/pgp_gpg.c	Mon Apr 20 21:03:13 2015 +0200
     4.2 +++ b/src/pgp_gpg.c	Tue Apr 21 08:37:01 2015 +0200
     4.3 @@ -1323,7 +1323,7 @@
     4.4  }
     4.5  
     4.6  typedef struct _renew_state {
     4.7 -    enum state_t {
     4.8 +    enum {
     4.9          renew_command = 0,
    4.10          renew_date,
    4.11          renew_secret_key,
    4.12 @@ -1490,18 +1490,180 @@
    4.13      return PEP_STATUS_OK;
    4.14  }
    4.15  
    4.16 -PEP_STATUS pgp_revoke_key(PEP_SESSION session, const char *fpr)
    4.17 +typedef struct _revoke_state {
    4.18 +    enum {
    4.19 +        revoke_command = 0,
    4.20 +        revoke_approve,
    4.21 +        revoke_reason_code,
    4.22 +        revoke_reason_text,
    4.23 +        revoke_reason_ok,
    4.24 +        revoke_quit,
    4.25 +        revoke_save,
    4.26 +        revoke_exit,
    4.27 +        revoke_error = -1
    4.28 +    } state;
    4.29 +    const char *reason_ref;
    4.30 +} revoke_state;
    4.31 +
    4.32 +static bool isemptystring(const char *str)
    4.33 +{
    4.34 +    if (str == NULL)
    4.35 +        return true;
    4.36 +
    4.37 +    for (; str; str++) {
    4.38 +        if (*str != ' ' && *str != '\t' && *str != '\n')
    4.39 +            return false;
    4.40 +    }
    4.41 +
    4.42 +    return true;
    4.43 +}
    4.44 +
    4.45 +static gpgme_error_t revoke_fsm(
    4.46 +        void *_handle,
    4.47 +        gpgme_status_code_t statuscode,
    4.48 +        const char *args,
    4.49 +        int fd
    4.50 +    )
    4.51 +{
    4.52 +    revoke_state *handle = _handle;
    4.53 +
    4.54 +    switch (handle->state) {
    4.55 +        case revoke_command:
    4.56 +            if (statuscode == GPGME_STATUS_GET_LINE) {
    4.57 +                assert(strcmp(args, "keyedit.prompt") == 0);
    4.58 +                if (strcmp(args, "keyedit.prompt")) {
    4.59 +                    handle->state = revoke_error;
    4.60 +                    return GPG_ERR_GENERAL;
    4.61 +                }
    4.62 +                write(fd, "revkey\n", 7);
    4.63 +                handle->state = revoke_approve;
    4.64 +            }
    4.65 +            break;
    4.66 +
    4.67 +        case revoke_approve:
    4.68 +            if (statuscode == GPGME_STATUS_GET_BOOL) {
    4.69 +                assert(strcmp(args, "keyedit.revoke.subkey.okay") == 0);
    4.70 +                if (strcmp(args, "keyedit.revoke.subkey.okay")) {
    4.71 +                    handle->state = revoke_error;
    4.72 +                    return GPG_ERR_GENERAL;
    4.73 +                }
    4.74 +                write(fd, "Y\n", 2);
    4.75 +                handle->state = revoke_reason_code;
    4.76 +            }
    4.77 +            break;
    4.78 +
    4.79 +        case revoke_reason_code:
    4.80 +            if (statuscode == GPGME_STATUS_GET_LINE) {
    4.81 +                assert(strcmp(args, "ask_revocation_reason.code") == 0);
    4.82 +                if (strcmp(args, "ask_revocation_reason.code")) {
    4.83 +                    handle->state = revoke_error;
    4.84 +                    return GPG_ERR_GENERAL;
    4.85 +                }
    4.86 +                write(fd, "1\n", 2);
    4.87 +                handle->state = revoke_reason_text;
    4.88 +            }
    4.89 +            break;
    4.90 +
    4.91 +        case revoke_reason_text:
    4.92 +            if (statuscode == GPGME_STATUS_GET_LINE) {
    4.93 +                assert(strcmp(args, "ask_revocation_reason.text") == 0);
    4.94 +                if (strcmp(args, "ask_revocation_reason.text")) {
    4.95 +                    handle->state = revoke_error;
    4.96 +                    return GPG_ERR_GENERAL;
    4.97 +                }
    4.98 +                if (isemptystring(handle->reason_ref))
    4.99 +                    write(fd, "\n", 1);
   4.100 +                else {
   4.101 +                    size_t len = strlen(handle->reason_ref);
   4.102 +                    write(fd, handle->reason_ref, len);
   4.103 +                    if (handle->reason_ref[len - 1] == '\n')
   4.104 +                        write(fd, "\n", 1);
   4.105 +                    else
   4.106 +                        write(fd, "\n\n", 2);
   4.107 +                }
   4.108 +                handle->state = revoke_reason_ok;
   4.109 +            }
   4.110 +            break;
   4.111 +
   4.112 +        case revoke_reason_ok:
   4.113 +            if (statuscode == GPGME_STATUS_GET_BOOL) {
   4.114 +                assert(strcmp(args, "ask_revocation_reason.okay") == 0);
   4.115 +                if (strcmp(args, "ask_revocation_reason.okay")) {
   4.116 +                    handle->state = revoke_error;
   4.117 +                    return GPG_ERR_GENERAL;
   4.118 +                }
   4.119 +                write(fd, "Y\n", 2);
   4.120 +                handle->state = revoke_quit;
   4.121 +            }
   4.122 +            break;
   4.123 +
   4.124 +        case revoke_quit:
   4.125 +            if (statuscode == GPGME_STATUS_GET_LINE) {
   4.126 +                assert(strcmp(args, "keyedit.prompt") == 0);
   4.127 +                if (strcmp(args, "keyedit.prompt")) {
   4.128 +                    handle->state = revoke_error;
   4.129 +                    return GPG_ERR_GENERAL;
   4.130 +                }
   4.131 +                write(fd, "quit\n", 5);
   4.132 +                handle->state = revoke_save;
   4.133 +            }
   4.134 +            break;
   4.135 +
   4.136 +        case revoke_save:
   4.137 +            if (statuscode == GPGME_STATUS_GET_BOOL) {
   4.138 +                assert(strcmp(args, "keyedit.save.okay") == 0);
   4.139 +                if (strcmp(args, "keyedit.save.okay")) {
   4.140 +                    handle->state = revoke_error;
   4.141 +                    return GPG_ERR_GENERAL;
   4.142 +                }
   4.143 +                write(fd, "Y\n", 2);
   4.144 +                handle->state = revoke_exit;
   4.145 +            }
   4.146 +            break;
   4.147 +
   4.148 +        case revoke_exit:
   4.149 +            break;
   4.150 +
   4.151 +        case revoke_error:
   4.152 +            return GPG_ERR_GENERAL;
   4.153 +    }
   4.154 +
   4.155 +    return GPG_ERR_NO_ERROR;
   4.156 +}
   4.157 +
   4.158 +PEP_STATUS pgp_revoke_key(
   4.159 +        PEP_SESSION session,
   4.160 +        const char *fpr,
   4.161 +        const char *reason
   4.162 +    )
   4.163  {
   4.164      PEP_STATUS status = PEP_STATUS_OK;
   4.165 +    gpgme_error_t gpgme_error;
   4.166      gpgme_key_t key;
   4.167 -    
   4.168 +    gpgme_data_t output;
   4.169 +    revoke_state handle;
   4.170 +
   4.171      assert(session);
   4.172      assert(fpr);
   4.173  
   4.174 +    memset(&handle, 0, sizeof(revoke_state));
   4.175 +
   4.176      status = find_single_key(session, fpr, &key);
   4.177      if (status != PEP_STATUS_OK)
   4.178          return status;
   4.179  
   4.180 +    struct gpgme_data_cbs data_cbs;
   4.181 +    memset(&data_cbs, 0, sizeof(struct gpgme_data_cbs));
   4.182 +    data_cbs.write = _nullwriter;
   4.183 +    gpgme_data_new_from_cbs(&output, &data_cbs, &handle);
   4.184 +
   4.185 +    gpgme_error = gpgme_op_edit(session->ctx, key, revoke_fsm, &handle,
   4.186 +            output);
   4.187 +    assert(gpgme_error == GPG_ERR_NO_ERROR);
   4.188 +
   4.189 +    gpg.gpgme_data_release(output);
   4.190 +    gpg.gpgme_key_unref(key);
   4.191 +
   4.192      return PEP_STATUS_OK;
   4.193  }
   4.194  
     5.1 --- a/src/pgp_gpg.h	Mon Apr 20 21:03:13 2015 +0200
     5.2 +++ b/src/pgp_gpg.h	Tue Apr 21 08:37:01 2015 +0200
     5.3 @@ -52,5 +52,9 @@
     5.4          const timestamp *ts
     5.5      );
     5.6  
     5.7 -PEP_STATUS pgp_revoke_key(PEP_SESSION session, const char *fpr);
     5.8 +PEP_STATUS pgp_revoke_key(
     5.9 +        PEP_SESSION session,
    5.10 +        const char *fpr,
    5.11 +        const char *reason
    5.12 +    );
    5.13  
     6.1 --- a/test/keyedit_test.cc	Mon Apr 20 21:03:13 2015 +0200
     6.2 +++ b/test/keyedit_test.cc	Tue Apr 21 08:37:01 2015 +0200
     6.3 @@ -22,7 +22,7 @@
     6.4  
     6.5      // generate test key
     6.6  
     6.7 -    cout << "\ngenerating key for expire test\n";
     6.8 +    cout << "\ngenerating key for keyedit test\n";
     6.9      pEp_identity *identity = new_identity(
    6.10              "expire@dingens.org",
    6.11              NULL,
    6.12 @@ -52,6 +52,13 @@
    6.13  
    6.14      cout << "key renewed.\n";
    6.15  
    6.16 +    cout << "key will be revoked\n";
    6.17 +    PEP_STATUS status3 = revoke_key(session, key.c_str(), "revoke test");
    6.18 +    cout << "revoke_key() exited with " << status3 << "\n";
    6.19 +    assert(status3 == PEP_STATUS_OK);
    6.20 +    
    6.21 +    cout << "key revoked.\n";
    6.22 +
    6.23      cout << "deleting key pair " << key.c_str() << "\n";
    6.24      PEP_STATUS delete_status = delete_keypair(session, key.c_str());
    6.25      cout << "delete_keypair() exits with " << delete_status << "\n";