slightly reworking initial PGP key import in case of GnuPG
authorVolker Birk <vb@pep.foundation>
Sat, 24 Feb 2018 20:21:37 +0100
changeset 253958c77e002d60
parent 2536 ee7e89ef6a18
child 2540 491b5de7cc3a
slightly reworking initial PGP key import in case of GnuPG
src/cryptotech.c
src/cryptotech.h
src/keymanagement.c
src/pEpEngine.c
src/pEpEngine.h
src/pgp_gpg.c
     1.1 --- a/src/cryptotech.c	Sat Feb 24 16:51:55 2018 +0100
     1.2 +++ b/src/cryptotech.c	Sat Feb 24 20:21:37 2018 +0100
     1.3 @@ -53,7 +53,6 @@
     1.4          cryptotech[PEP_crypt_OpenPGP].key_created = pgp_key_created;
     1.5          cryptotech[PEP_crypt_OpenPGP].contains_priv_key = pgp_contains_priv_key;
     1.6          cryptotech[PEP_crypt_OpenPGP].find_private_keys = pgp_find_private_keys;
     1.7 -        cryptotech[PEP_crypt_OpenPGP].import_trusted_own_keys = pgp_import_ultimately_trusted_keypairs;
     1.8  #ifdef PGP_BINARY_PATH
     1.9          cryptotech[PEP_crypt_OpenPGP].binary_path = PGP_BINARY_PATH;
    1.10  #endif
     2.1 --- a/src/cryptotech.h	Sat Feb 24 16:51:55 2018 +0100
     2.2 +++ b/src/cryptotech.h	Sat Feb 24 20:21:37 2018 +0100
     2.3 @@ -89,10 +89,6 @@
     2.4      PEP_SESSION session, const char *pattern, stringlist_t **keylist
     2.5  );
     2.6  
     2.7 -typedef PEP_STATUS(*import_trusted_own_keys_t)(
     2.8 -    PEP_SESSION session
     2.9 -);
    2.10 -
    2.11  typedef struct _PEP_cryptotech_t {
    2.12      uint8_t id;
    2.13      // the following are default values; comm_type may vary with key length or b0rken crypto
    2.14 @@ -118,7 +114,6 @@
    2.15      binary_path_t binary_path;
    2.16      contains_priv_key_t contains_priv_key;
    2.17      find_private_keys_t find_private_keys;
    2.18 -    import_trusted_own_keys_t import_trusted_own_keys;
    2.19  } PEP_cryptotech_t;
    2.20  
    2.21  extern PEP_cryptotech_t cryptotech[PEP_crypt__count];
     3.1 --- a/src/keymanagement.c	Sat Feb 24 16:51:55 2018 +0100
     3.2 +++ b/src/keymanagement.c	Sat Feb 24 20:21:37 2018 +0100
     3.3 @@ -1749,3 +1749,96 @@
     3.4      sqlite3_reset(session->is_mistrusted_key);
     3.5      return status;
     3.6  }
     3.7 +
     3.8 +#ifdef USE_GPG
     3.9 +PEP_STATUS pgp_find_trusted_private_keys(
    3.10 +        PEP_SESSION session, stringlist_t **keylist
    3.11 +    );
    3.12 +
    3.13 +enum _pgp_thing {
    3.14 +    _pgp_none = 0,
    3.15 +    _pgp_fpr,
    3.16 +    _pgp_email,
    3.17 +    _pgp_name
    3.18 +};
    3.19 +
    3.20 +static enum _pgp_thing _pgp_thing_next(enum _pgp_thing thing)
    3.21 +{
    3.22 +    switch (thing) {
    3.23 +        case _pgp_fpr:
    3.24 +            return _pgp_email;
    3.25 +        case _pgp_email:
    3.26 +            return _pgp_name;
    3.27 +        case _pgp_name:
    3.28 +            return _pgp_fpr;
    3.29 +        default:
    3.30 +            return _pgp_fpr;
    3.31 +    }
    3.32 +}
    3.33 +
    3.34 +PEP_STATUS pgp_import_ultimately_trusted_keypairs(PEP_SESSION session) {
    3.35 +    assert(session);
    3.36 +    if (!session)
    3.37 +        return PEP_ILLEGAL_VALUE;
    3.38 +
    3.39 +    stringlist_t* priv_keylist = NULL;
    3.40 +    PEP_STATUS status = PEP_STATUS_OK;
    3.41 +
    3.42 +    // 1. get keys
    3.43 +    status = pgp_find_trusted_private_keys(session, &priv_keylist);
    3.44 +    if (status)
    3.45 +        return status;
    3.46 +
    3.47 +    pEp_identity *identity = NULL;
    3.48 +    stringlist_t *_sl;
    3.49 +    char *fpr;
    3.50 +    enum _pgp_thing thing = _pgp_none;
    3.51 +    for (_sl = priv_keylist; _sl && _sl->value; _sl = _sl->next) {
    3.52 +        thing = _pgp_thing_next(thing);
    3.53 +        switch (thing) {
    3.54 +            case _pgp_fpr:
    3.55 +                identity = new_identity(NULL, NULL, PEP_OWN_USERID, NULL);
    3.56 +                if (!identity)
    3.57 +                    status = PEP_OUT_OF_MEMORY;
    3.58 +                identity->me = true;
    3.59 +                fpr = strdup(_sl->value);
    3.60 +                assert(fpr);
    3.61 +                if (!fpr) {
    3.62 +                    status = PEP_OUT_OF_MEMORY;
    3.63 +                    free_identity(identity);
    3.64 +                }
    3.65 +                break;
    3.66 +            case _pgp_email:
    3.67 +                assert(identity);
    3.68 +                identity->address = strdup(_sl->value);
    3.69 +                assert(identity->address);
    3.70 +                if (!identity->address) {
    3.71 +                    status = PEP_OUT_OF_MEMORY;
    3.72 +                    free_identity(identity);
    3.73 +                }
    3.74 +                break;
    3.75 +            case _pgp_name:
    3.76 +                assert(identity);
    3.77 +                identity->username = strdup(_sl->value);
    3.78 +                assert(identity->username);
    3.79 +                if (!identity->username)
    3.80 +                    status = PEP_OUT_OF_MEMORY;
    3.81 +                else
    3.82 +                    status = set_own_key(session, identity, fpr);
    3.83 +                free_identity(identity);
    3.84 +                identity = NULL;
    3.85 +                break;
    3.86 +            default:
    3.87 +                assert(0);
    3.88 +                free_identity(identity);
    3.89 +                status = PEP_UNKNOWN_ERROR;
    3.90 +        }
    3.91 +        if (status)
    3.92 +            break;
    3.93 +    }
    3.94 +    
    3.95 +    free_stringlist(priv_keylist);
    3.96 +    return status;
    3.97 +}
    3.98 +#endif // USE_GPG
    3.99 +
     4.1 --- a/src/pEpEngine.c	Sat Feb 24 16:51:55 2018 +0100
     4.2 +++ b/src/pEpEngine.c	Sat Feb 24 20:21:37 2018 +0100
     4.3 @@ -486,6 +486,10 @@
     4.4    fprintf(stderr, "(%d) %s\n", iErrCode, zMsg);
     4.5  }
     4.6  
     4.7 +#ifdef USE_GPG
     4.8 +PEP_STATUS pgp_import_ultimately_trusted_keypairs(PEP_SESSION session);
     4.9 +#endif // USE_GPG
    4.10 +
    4.11  DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
    4.12  {
    4.13      PEP_STATUS status = PEP_STATUS_OK;
    4.14 @@ -1294,6 +1298,7 @@
    4.15  
    4.16      if (very_first)
    4.17      {
    4.18 +#ifdef USE_GPG
    4.19          // On first run, all private keys already present in PGP keyring 
    4.20          // are taken as own in order to seamlessly integrate with
    4.21          // pre-existing GPG setup.
    4.22 @@ -1306,7 +1311,8 @@
    4.23          // private keys have an 'unknown' trust designation in PGP).
    4.24  
    4.25          // We don't really worry about the status here.
    4.26 -        status = import_trusted_own_keys(_session);        
    4.27 +        status = pgp_import_ultimately_trusted_keypairs(_session);        
    4.28 +#endif // USE_GPG
    4.29      }
    4.30  
    4.31      // sync_session set to own session by default
    4.32 @@ -3825,14 +3831,6 @@
    4.33                                                                      keylist);
    4.34  }
    4.35  
    4.36 -PEP_STATUS import_trusted_own_keys(PEP_SESSION session) {
    4.37 -    assert(session);
    4.38 -    if (!session)
    4.39 -        return PEP_ILLEGAL_VALUE;
    4.40 -        
    4.41 -    return session->cryptotech[PEP_crypt_OpenPGP].import_trusted_own_keys(session); 
    4.42 -}
    4.43 -
    4.44  DYNAMIC_API const char* get_engine_version() {
    4.45      return PEP_ENGINE_VERSION;
    4.46  }
     5.1 --- a/src/pEpEngine.h	Sat Feb 24 16:51:55 2018 +0100
     5.2 +++ b/src/pEpEngine.h	Sat Feb 24 20:21:37 2018 +0100
     5.3 @@ -1248,8 +1248,6 @@
     5.4      
     5.5  PEP_STATUS refresh_userid_default_key(PEP_SESSION session, const char* user_id);
     5.6  
     5.7 -PEP_STATUS import_trusted_own_keys(PEP_SESSION session);
     5.8 -
     5.9  // This ONLY sets the *user* flag, and creates a shell identity if necessary.
    5.10  PEP_STATUS set_as_pep_user(PEP_SESSION session, pEp_identity* user);
    5.11  
     6.1 --- a/src/pgp_gpg.c	Sat Feb 24 16:51:55 2018 +0100
     6.2 +++ b/src/pgp_gpg.c	Sat Feb 24 20:21:37 2018 +0100
     6.3 @@ -1939,80 +1939,95 @@
     6.4      return _pgp_search_keys(session, pattern, keylist, 1);
     6.5  }
     6.6  
     6.7 -PEP_STATUS pgp_import_ultimately_trusted_keypairs(PEP_SESSION session) {
     6.8 -    assert(session);
     6.9 -    if (!session)
    6.10 +// this function is delivering a list of triples with fpr, email, name of all
    6.11 +// ultimatedly trusted private keys
    6.12 +
    6.13 +PEP_STATUS pgp_find_trusted_private_keys(
    6.14 +        PEP_SESSION session, stringlist_t **keylist
    6.15 +    )
    6.16 +{
    6.17 +    assert(session && keylist);
    6.18 +    if (!session || !keylist)
    6.19          return PEP_ILLEGAL_VALUE;
    6.20  
    6.21 -    stringlist_t* priv_keylist = NULL;
    6.22 +    *keylist = NULL;
    6.23 +
    6.24      gpgme_key_t key;
    6.25      gpgme_error_t gpgme_error;
    6.26 -    PEP_STATUS status = PEP_STATUS_OK;
    6.27 -    PEP_STATUS first_fail = PEP_STATUS_OK;
    6.28 -
    6.29 -
    6.30 -    // 1. get keys
    6.31 -    first_fail = pgp_find_private_keys(session, NULL, &priv_keylist);
    6.32 -
    6.33 -    bool has_already_failed = (first_fail != PEP_STATUS_OK);
    6.34 -
    6.35 -    if (!has_already_failed) {    
    6.36 -        stringlist_t* keylist_curr;    
    6.37 -        
    6.38 -        // 2. for each key
    6.39 -        for (keylist_curr = priv_keylist; keylist_curr; keylist_curr = keylist_curr->next) {
    6.40 -            // a. get key data
    6.41 -            if (!keylist_curr->value)
    6.42 -                continue;
    6.43 -    
    6.44 -            gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
    6.45 -            gpgme_error = _GPGERR(gpgme_error);
    6.46 -            assert(gpgme_error != GPG_ERR_ENOMEM);
    6.47 -            switch (gpgme_error) {
    6.48 -                case GPG_ERR_NO_ERROR:
    6.49 -                    break;
    6.50 -                case GPG_ERR_EOF:
    6.51 -                    first_fail = (has_already_failed ? first_fail : PEP_KEY_NOT_FOUND);
    6.52 -                    break;
    6.53 -                case GPG_ERR_INV_VALUE:
    6.54 -                    first_fail = (has_already_failed ? first_fail : PEP_ILLEGAL_VALUE);
    6.55 -                    break;
    6.56 -                case GPG_ERR_AMBIGUOUS_NAME:
    6.57 -                    first_fail = (has_already_failed ? first_fail : PEP_KEY_HAS_AMBIG_NAME);
    6.58 -                    break;
    6.59 -                case GPG_ERR_ENOMEM:
    6.60 -                    first_fail = (has_already_failed ? first_fail : PEP_OUT_OF_MEMORY);
    6.61 -                    break;
    6.62 -                default:
    6.63 -                    assert(0);
    6.64 -                    first_fail = (has_already_failed ? first_fail : PEP_UNKNOWN_ERROR);
    6.65 +
    6.66 +    stringlist_t *private_keylist = NULL;
    6.67 +    PEP_STATUS status = pgp_find_private_keys(session, NULL, &private_keylist);
    6.68 +    if (status)
    6.69 +        return status;
    6.70 +    if (!private_keylist || !private_keylist->value)
    6.71 +        return status;
    6.72 +
    6.73 +    stringlist_t *result_list = new_stringlist(NULL);
    6.74 +    if (!result_list)
    6.75 +        return PEP_OUT_OF_MEMORY;
    6.76 +    stringlist_t *_result_list = result_list;
    6.77 +
    6.78 +    stringlist_t *keylist_curr;
    6.79 +    for (keylist_curr = private_keylist; keylist_curr && keylist_curr->value; keylist_curr = keylist_curr->next) {
    6.80 +        // a. get key data
    6.81 +        gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
    6.82 +        gpgme_error = _GPGERR(gpgme_error);
    6.83 +        assert(gpgme_error != GPG_ERR_ENOMEM);
    6.84 +        switch (gpgme_error) {
    6.85 +            case GPG_ERR_NO_ERROR:
    6.86 +                break;
    6.87 +            case GPG_ERR_EOF:
    6.88 +                status = PEP_KEY_NOT_FOUND;
    6.89 +                break;
    6.90 +            case GPG_ERR_INV_VALUE:
    6.91 +                status = PEP_ILLEGAL_VALUE;
    6.92 +                break;
    6.93 +            case GPG_ERR_AMBIGUOUS_NAME:
    6.94 +                status = PEP_KEY_HAS_AMBIG_NAME;
    6.95 +                break;
    6.96 +            case GPG_ERR_ENOMEM:
    6.97 +                free_stringlist(result_list);
    6.98 +                free_stringlist(private_keylist);
    6.99 +                return PEP_OUT_OF_MEMORY;
   6.100 +            default:
   6.101 +                assert(0);
   6.102 +                status = PEP_UNKNOWN_ERROR;
   6.103 +        }
   6.104 +        if (key && gpgme_error == GPG_ERR_NO_ERROR) {
   6.105 +            if (key->revoked || key->disabled) {
   6.106 +                status = PEP_KEY_UNSUITABLE;
   6.107              }
   6.108 -            if (key && gpgme_error == GPG_ERR_NO_ERROR) {
   6.109 -                if (key->revoked || key->disabled)
   6.110 -                    first_fail = (has_already_failed ? first_fail : PEP_KEY_UNSUITABLE);
   6.111 -                else {
   6.112 -                    if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
   6.113 -                        if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
   6.114 -                                            key->uids && key->uids->address) { 
   6.115 -                            pEp_identity* new_id = new_identity(key->uids->address,
   6.116 -                                                                key->fpr,
   6.117 -                                                                PEP_OWN_USERID,
   6.118 -                                                                key->uids->name);
   6.119 -                            if (!new_id)
   6.120 -                                status = PEP_OUT_OF_MEMORY;
   6.121 -                            else    
   6.122 -                                status = myself(session, new_id);
   6.123 -                                
   6.124 -                            first_fail = (has_already_failed ? first_fail : status);
   6.125 +            else {
   6.126 +                if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
   6.127 +                    if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
   6.128 +                            key->uids && key->uids->email && key->uids->name) { 
   6.129 +                        _result_list = stringlist_add(_result_list, key->fpr);
   6.130 +                        if (!_result_list) {
   6.131 +                            free_stringlist(result_list);
   6.132 +                            free_stringlist(private_keylist);
   6.133 +                            return PEP_OUT_OF_MEMORY;
   6.134 +                        }
   6.135 +                        _result_list = stringlist_add(_result_list, key->uids->email);
   6.136 +                        if (!_result_list) {
   6.137 +                            free_stringlist(result_list);
   6.138 +                            free_stringlist(private_keylist);
   6.139 +                            return PEP_OUT_OF_MEMORY;
   6.140 +                        }
   6.141 +                        _result_list = stringlist_add(_result_list, key->uids->name);
   6.142 +                        if (!_result_list) {
   6.143 +                            free_stringlist(result_list);
   6.144 +                            free_stringlist(private_keylist);
   6.145 +                            return PEP_OUT_OF_MEMORY;
   6.146                          }
   6.147                      }
   6.148                  }
   6.149              }
   6.150 -            
   6.151 -            has_already_failed = first_fail != PEP_STATUS_OK;
   6.152          }
   6.153      }
   6.154 -    return first_fail;
   6.155 +
   6.156 +    free_stringlist(private_keylist);
   6.157 +    *keylist = result_list;
   6.158 +    return PEP_STATUS_OK;
   6.159  }
   6.160  
   6.161  PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)