ENGINE-84: working on ensuring keypairs missing private keys are not selected for encryption candidates ENGINE-84
authorKrista Grothoff <krista@pep-project.org>
Tue, 08 Nov 2016 00:12:17 +0100
branchENGINE-84
changeset 1357b1677cd84729
parent 1352 239640860531
child 1358 ff3053a671dc
ENGINE-84: working on ensuring keypairs missing private keys are not selected for encryption candidates
src/cryptotech.c
src/cryptotech.h
src/keymanagement.c
src/keymanagement.h
src/pEpEngine.c
src/pEpEngine.h
src/pgp_gpg.c
src/pgp_gpg.h
     1.1 --- a/src/cryptotech.c	Sun Nov 06 22:55:37 2016 +0100
     1.2 +++ b/src/cryptotech.c	Tue Nov 08 00:12:17 2016 +0100
     1.3 @@ -47,7 +47,8 @@
     1.4          cryptotech[PEP_crypt_OpenPGP].key_expired = pgp_key_expired;
     1.5          cryptotech[PEP_crypt_OpenPGP].key_revoked = pgp_key_revoked;
     1.6          cryptotech[PEP_crypt_OpenPGP].key_created = pgp_key_created;
     1.7 -        cryptotech[PEP_crypt_OpenPGP].pair_has_private = pgp_pair_has_private;
     1.8 +        cryptotech[PEP_crypt_OpenPGP].contains_priv_key = pgp_contains_priv_key;
     1.9 +        cryptotech[PEP_crypt_OpenPGP].find_private_keys = pgp_find_private_keys;
    1.10  #ifdef PGP_BINARY_PATH
    1.11          cryptotech[PEP_crypt_OpenPGP].binary_path = PGP_BINARY_PATH;
    1.12  #endif
     2.1 --- a/src/cryptotech.h	Sun Nov 06 22:55:37 2016 +0100
     2.2 +++ b/src/cryptotech.h	Tue Nov 08 00:12:17 2016 +0100
     2.3 @@ -72,9 +72,13 @@
     2.4  
     2.5  typedef PEP_STATUS (*binary_path_t)(const char **path);
     2.6  
     2.7 -typedef PEP_STATUS (*pair_has_private_t)(PEP_SESSION session, const char *fpr,
     2.8 +typedef PEP_STATUS (*contains_priv_key_t)(PEP_SESSION session, const char *fpr,
     2.9          bool *has_private);
    2.10  
    2.11 +typedef PEP_STATUS (*find_private_keys_t)(
    2.12 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist
    2.13 +);
    2.14 +
    2.15  typedef struct _PEP_cryptotech_t {
    2.16      uint8_t id;
    2.17      // the following are default values; comm_type may vary with key length or b0rken crypto
    2.18 @@ -97,7 +101,8 @@
    2.19      key_revoked_t key_revoked;
    2.20      key_created_t key_created;
    2.21      binary_path_t binary_path;
    2.22 -    pair_has_private_t pair_has_private;
    2.23 +    contains_priv_key_t contains_priv_key;
    2.24 +    find_private_keys_t find_private_keys;
    2.25  } PEP_cryptotech_t;
    2.26  
    2.27  extern PEP_cryptotech_t cryptotech[PEP_crypt__count];
     3.1 --- a/src/keymanagement.c	Sun Nov 06 22:55:37 2016 +0100
     3.2 +++ b/src/keymanagement.c	Tue Nov 08 00:12:17 2016 +0100
     3.3 @@ -313,7 +313,7 @@
     3.4      free(identity->fpr);
     3.5      identity->fpr = NULL;
     3.6  
     3.7 -    status = find_keys(session, identity->address, &keylist);
     3.8 +    status = find_private_keys(session, identity->address, &keylist);
     3.9      assert(status != PEP_OUT_OF_MEMORY);
    3.10      if (status == PEP_OUT_OF_MEMORY)
    3.11          return PEP_OUT_OF_MEMORY;
    3.12 @@ -378,6 +378,25 @@
    3.13      return PEP_STATUS_OK;
    3.14  }
    3.15  
    3.16 +PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
    3.17 +                                bool* is_usable) {
    3.18 +    
    3.19 +    bool dont_use_fpr = true;
    3.20 +    
    3.21 +    PEP_STATUS status = blacklist_is_listed(session, fpr, &dont_use_fpr);
    3.22 +    if (!dont_use_fpr) {
    3.23 +        // Make sure there is a *private* key associated with this fpr
    3.24 +        bool has_private = false;
    3.25 +        status = contains_priv_key(session, fpr, &has_private);
    3.26 +        // TODO: check status
    3.27 +        dont_use_fpr = !has_private;
    3.28 +    }
    3.29 +    
    3.30 +    *is_usable = !dont_use_fpr;
    3.31 +    
    3.32 +    return status;
    3.33 +}
    3.34 +
    3.35  DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
    3.36  {
    3.37      pEp_identity *stored_identity;
    3.38 @@ -417,49 +436,73 @@
    3.39      assert(status != PEP_OUT_OF_MEMORY);
    3.40      if (status == PEP_OUT_OF_MEMORY)
    3.41          return PEP_OUT_OF_MEMORY;
    3.42 +
    3.43 +    bool dont_use_stored_fpr = true;
    3.44 +    bool dont_use_input_fpr = true;
    3.45      
    3.46      if (stored_identity)
    3.47      {
    3.48          if (EMPTYSTR(identity->fpr)) {
    3.49              
    3.50 -            // First check to see if it's blacklisted?
    3.51 -            char* stored_fpr = stored_identity->fpr;
    3.52 +            bool has_private = false;
    3.53              
    3.54 -            bool dont_use_fpr = false;
    3.55 +            status = _has_usable_priv_key(session, stored_identity->fpr, &has_private); 
    3.56              
    3.57 -            status = blacklist_is_listed(session, stored_fpr, &dont_use_fpr);
    3.58 -            if (!dont_use_fpr) {
    3.59 -                // Make sure there is a *private* key associated with this fpr
    3.60 -            }
    3.61 -            
    3.62 -            identity->fpr = strdup(stored_identity->fpr);
    3.63 -            assert(identity->fpr);
    3.64 -            if (identity->fpr == NULL)
    3.65 -            {
    3.66 -                return PEP_OUT_OF_MEMORY;
    3.67 +            if (has_private) {
    3.68 +                identity->fpr = strdup(stored_identity->fpr);
    3.69 +                assert(identity->fpr);
    3.70 +                if (identity->fpr == NULL)
    3.71 +                {
    3.72 +                    return PEP_OUT_OF_MEMORY;
    3.73 +                }
    3.74 +                dont_use_stored_fpr = false;
    3.75              }
    3.76          }
    3.77 -
    3.78 +        
    3.79          identity->flags = stored_identity->flags;
    3.80      }
    3.81 -    else if (!EMPTYSTR(identity->fpr))
    3.82 +    
    3.83 +    if (dont_use_stored_fpr && !EMPTYSTR(identity->fpr))
    3.84      {
    3.85          // App must have a good reason to give fpr, such as explicit
    3.86          // import of private key, or similar.
    3.87  
    3.88          // Take given fpr as-is.
    3.89  
    3.90 -        identity->flags = 0;
    3.91 +        // BUT:
    3.92 +        // First check to see if it's blacklisted or private part is missing?
    3.93 +        bool has_private = false;
    3.94 +        
    3.95 +        status = _has_usable_priv_key(session, identity->fpr, &has_private); 
    3.96 +        
    3.97 +        if (has_private) {
    3.98 +            identity->flags = 0;
    3.99 +            dont_use_input_fpr = false;
   3.100 +        }
   3.101      }
   3.102 -    else
   3.103 +    
   3.104 +    // Ok, we failed to get keys either way, so let's elect one.
   3.105 +    if (dont_use_input_fpr && dont_use_stored_fpr)
   3.106      {
   3.107          status = elect_ownkey(session, identity);
   3.108          assert(status == PEP_STATUS_OK);
   3.109          if (status != PEP_STATUS_OK) {
   3.110              return status;
   3.111          }
   3.112 -
   3.113 -        identity->flags = 0;
   3.114 +        
   3.115 +        // Check to see if it's blacklisted or private part is missing
   3.116 +        bool has_private = false;
   3.117 +        
   3.118 +        status = _has_usable_priv_key(session, identity->fpr, &has_private); 
   3.119 +        
   3.120 +        if (has_private) {
   3.121 +            identity->flags = 0;
   3.122 +            dont_use_input_fpr = false;
   3.123 +        }
   3.124 +        else { // OK, we've tried everything. Time to generate new keys.
   3.125 +            
   3.126 +        }
   3.127 +        
   3.128      }
   3.129  
   3.130      bool revoked = false;
   3.131 @@ -844,3 +887,16 @@
   3.132      return status;
   3.133  }
   3.134  
   3.135 +
   3.136 +PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
   3.137 +                             bool *has_private) {
   3.138 +
   3.139 +    assert(session);
   3.140 +    assert(fpr);
   3.141 +    assert(has_private);
   3.142 +    
   3.143 +    if (!(session && fpr && has_private))
   3.144 +        return PEP_ILLEGAL_VALUE;
   3.145 +
   3.146 +    return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
   3.147 +}
   3.148 \ No newline at end of file
     4.1 --- a/src/keymanagement.h	Sun Nov 06 22:55:37 2016 +0100
     4.2 +++ b/src/keymanagement.h	Tue Nov 08 00:12:17 2016 +0100
     4.3 @@ -185,6 +185,9 @@
     4.4          identity_list **own_identities
     4.5      );
     4.6  
     4.7 +PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
     4.8 +                             bool *has_private);
     4.9 +
    4.10  #ifdef __cplusplus
    4.11  }
    4.12  #endif
     5.1 --- a/src/pEpEngine.c	Sun Nov 06 22:55:37 2016 +0100
     5.2 +++ b/src/pEpEngine.c	Tue Nov 08 00:12:17 2016 +0100
     5.3 @@ -2107,6 +2107,16 @@
     5.4              created);
     5.5  }
     5.6  
     5.7 +PEP_STATUS find_private_keys(PEP_SESSION session, const char* pattern,
     5.8 +                             stringlist_t **keylist) {
     5.9 +    assert(session && pattern && keylist);
    5.10 +    if (!(session && pattern && keylist))
    5.11 +        return PEP_ILLEGAL_VALUE;
    5.12 +    
    5.13 +    return session->cryptotech[PEP_crypt_OpenPGP].find_private_keys(session, pattern,
    5.14 +                                                                    keylist);
    5.15 +}
    5.16 +
    5.17  DYNAMIC_API const char* get_engine_version() {
    5.18      return PEP_ENGINE_VERSION;
    5.19  }
     6.1 --- a/src/pEpEngine.h	Sun Nov 06 22:55:37 2016 +0100
     6.2 +++ b/src/pEpEngine.h	Tue Nov 08 00:12:17 2016 +0100
     6.3 @@ -999,6 +999,20 @@
     6.4      );
     6.5  
     6.6  
     6.7 +// find_keys() - find keys in keyring
     6.8 +//
     6.9 +//  parameters:
    6.10 +//      session (in)            session handle
    6.11 +//      pattern (in)            key id, user id or address to search for as
    6.12 +//                              UTF-8 string
    6.13 +//      keylist (out)           list of fingerprints found or NULL on error
    6.14 +//
    6.15 +//  caveat:
    6.16 +//        the ownerships of keylist isgoing to the caller
    6.17 +//        the caller must use free_stringlist() to free it
    6.18 +PEP_STATUS find_private_keys(PEP_SESSION session, const char* pattern,
    6.19 +                             stringlist_t **keylist);
    6.20 +
    6.21  // get_engine_version() - returns the current version of pEpEngine (this is different
    6.22  //                        from the pEp protocol version!)
    6.23  //
     7.1 --- a/src/pgp_gpg.c	Sun Nov 06 22:55:37 2016 +0100
     7.2 +++ b/src/pgp_gpg.c	Tue Nov 08 00:12:17 2016 +0100
     7.3 @@ -1411,61 +1411,61 @@
     7.4      return PEP_STATUS_OK;
     7.5  }
     7.6  
     7.7 -PEP_STATUS pgp_find_keys(
     7.8 -    PEP_SESSION session, const char *pattern, stringlist_t **keylist
     7.9 -    )
    7.10 -{
    7.11 +
    7.12 +static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
    7.13 +                            stringlist_t** keylist,
    7.14 +                            int private_only) {
    7.15      gpgme_error_t gpgme_error;
    7.16      gpgme_key_t key;
    7.17 -
    7.18 +    
    7.19      assert(session);
    7.20      assert(pattern);
    7.21      assert(keylist);
    7.22 -
    7.23 +    
    7.24      *keylist = NULL;
    7.25 -
    7.26 -    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
    7.27 +    
    7.28 +    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
    7.29      gpgme_error = _GPGERR(gpgme_error);
    7.30      switch (gpgme_error) {
    7.31 -    case GPG_ERR_NO_ERROR:
    7.32 -        break;
    7.33 -    case GPG_ERR_INV_VALUE:
    7.34 -        assert(0);
    7.35 -        return PEP_UNKNOWN_ERROR;
    7.36 -    default:
    7.37 -        gpg.gpgme_op_keylist_end(session->ctx);
    7.38 -        return PEP_GET_KEY_FAILED;
    7.39 +        case GPG_ERR_NO_ERROR:
    7.40 +            break;
    7.41 +        case GPG_ERR_INV_VALUE:
    7.42 +            assert(0);
    7.43 +            return PEP_UNKNOWN_ERROR;
    7.44 +        default:
    7.45 +            gpg.gpgme_op_keylist_end(session->ctx);
    7.46 +            return PEP_GET_KEY_FAILED;
    7.47      };
    7.48 -
    7.49 +    
    7.50      stringlist_t *_keylist = new_stringlist(NULL);
    7.51      stringlist_t *_k = _keylist;
    7.52 -
    7.53 +    
    7.54      do {
    7.55          gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
    7.56          gpgme_error = _GPGERR(gpgme_error);
    7.57          assert(gpgme_error != GPG_ERR_INV_VALUE);
    7.58          switch (gpgme_error) {
    7.59 -        case GPG_ERR_EOF:
    7.60 -            break;
    7.61 -        case GPG_ERR_NO_ERROR:
    7.62 -            assert(key);
    7.63 -            assert(key->subkeys);
    7.64 -            char *fpr = key->subkeys->fpr;
    7.65 -            assert(fpr);
    7.66 -            _k = stringlist_add(_k, fpr);
    7.67 -            assert(_k);
    7.68 -            if (_k != NULL)
    7.69 +            case GPG_ERR_EOF:
    7.70                  break;
    7.71 -        case GPG_ERR_ENOMEM:
    7.72 -            free_stringlist(_keylist);
    7.73 -            gpg.gpgme_op_keylist_end(session->ctx);
    7.74 -            return PEP_OUT_OF_MEMORY;
    7.75 -        default:
    7.76 -            gpg.gpgme_op_keylist_end(session->ctx);
    7.77 -            return PEP_UNKNOWN_ERROR;
    7.78 +            case GPG_ERR_NO_ERROR:
    7.79 +                assert(key);
    7.80 +                assert(key->subkeys);
    7.81 +                char *fpr = key->subkeys->fpr;
    7.82 +                assert(fpr);
    7.83 +                _k = stringlist_add(_k, fpr);
    7.84 +                assert(_k);
    7.85 +                if (_k != NULL)
    7.86 +                    break;
    7.87 +            case GPG_ERR_ENOMEM:
    7.88 +                free_stringlist(_keylist);
    7.89 +                gpg.gpgme_op_keylist_end(session->ctx);
    7.90 +                return PEP_OUT_OF_MEMORY;
    7.91 +            default:
    7.92 +                gpg.gpgme_op_keylist_end(session->ctx);
    7.93 +                return PEP_UNKNOWN_ERROR;
    7.94          };
    7.95      } while (gpgme_error != GPG_ERR_EOF);
    7.96 -
    7.97 +    
    7.98      gpg.gpgme_op_keylist_end(session->ctx);
    7.99      if (_keylist->value == NULL) {
   7.100          free_stringlist(_keylist);
   7.101 @@ -1475,6 +1475,20 @@
   7.102      return PEP_STATUS_OK;
   7.103  }
   7.104  
   7.105 +PEP_STATUS pgp_find_keys(
   7.106 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist
   7.107 +    )
   7.108 +{
   7.109 +    return _pgp_search_keys(session, pattern, keylist, 0);
   7.110 +}    
   7.111 +
   7.112 +PEP_STATUS pgp_find_private_keys(
   7.113 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist
   7.114 +)
   7.115 +{
   7.116 +    return _pgp_search_keys(session, pattern, keylist, 1);
   7.117 +}
   7.118 +
   7.119  PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
   7.120  {
   7.121      gpgme_error_t gpgme_error;
   7.122 @@ -2118,11 +2132,11 @@
   7.123      return PEP_STATUS_OK;
   7.124  }
   7.125  
   7.126 -PEP_STATUS pgp_pair_has_private(PEP_SESSION session, const char *fpr,
   7.127 +PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
   7.128          bool *has_private) {
   7.129 -    status = PEP_STATUS_OK;
   7.130 -    gpg_key_t output_key;
   7.131 -    gpgme_error_t gpgerr = gpgme_get_key(session->ctx, fpr, &output_key, true);
   7.132 +    PEP_STATUS status = PEP_STATUS_OK;
   7.133 +    gpgme_key_t output_key;
   7.134 +    gpgme_error_t gpgerr = gpg.gpgme_get_key(session->ctx, fpr, &output_key, true);
   7.135      *has_private = false;
   7.136      switch (gpgerr) {
   7.137          case GPG_ERR_EOF:
     8.1 --- a/src/pgp_gpg.h	Sun Nov 06 22:55:37 2016 +0100
     8.2 +++ b/src/pgp_gpg.h	Tue Nov 08 00:12:17 2016 +0100
     8.3 @@ -85,6 +85,15 @@
     8.4          time_t *created
     8.5      );
     8.6  
     8.7 +PEP_STATUS pgp_contains_priv_key(
     8.8 +        PEP_SESSION session, 
     8.9 +        const char *fpr,
    8.10 +        bool *has_private);
    8.11 +
    8.12 +PEP_STATUS pgp_find_private_keys(
    8.13 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist
    8.14 +);
    8.15 +
    8.16  PEP_STATUS pgp_binary(const char **path);
    8.17  #define PGP_BINARY_PATH pgp_binary
    8.18