merge sync, incl PEP_HOME ENGINE-524
authorClaudio Luck <claudio.luck@pep.foundation>
Mon, 13 May 2019 19:30:36 +0200
branchENGINE-524
changeset 367280b56b8c68dd
parent 3638 4ba9bd8b80c1
parent 3668 43632a5474fb
child 3673 04873e5d64f4
merge sync, incl PEP_HOME
src/pgp_sequoia.c
src/platform_unix.c
     1.1 --- a/Makefile	Mon May 06 17:52:20 2019 +0200
     1.2 +++ b/Makefile	Mon May 13 19:30:36 2019 +0200
     1.3 @@ -19,13 +19,6 @@
     1.4      $(info ================================================)
     1.5  endif
     1.6  
     1.7 -ifneq ($(MAKE_VERSION),$(word 2,$(sort $(MAKE_VERSION) 4)))
     1.8 -    $(warning ================================================)
     1.9 -    $(warning You are using a make version older than 4. This might cause problems.)
    1.10 -    $(warning ================================================)
    1.11 -endif
    1.12 -
    1.13 -
    1.14  .PHONY: all sync asn1 build install dbinstall uninstall clean tags test package db
    1.15  
    1.16  build: asn1
     2.1 --- a/asn.1/Makefile	Mon May 06 17:52:20 2019 +0200
     2.2 +++ b/asn.1/Makefile	Mon May 13 19:30:36 2019 +0200
     2.3 @@ -9,7 +9,7 @@
     2.4  .PHONY: all clean install uninstall
     2.5  
     2.6  all: Sync.c
     2.7 -	make libasn1.a
     2.8 +	$(MAKE) libasn1.a
     2.9  
    2.10  libasn1.a: $(ALL_OBJECTS)
    2.11  	$(AR) -rc $@ $(ALL_OBJECTS)
    2.12 @@ -20,6 +20,7 @@
    2.13  Sync.c: sync.asn1 keysync.asn1 pEp.asn1
    2.14  	$(ASN1C) -gen-PER -fincludes-quoted -fcompound-names -pdu=auto pEp.asn1 keysync.asn1 $<
    2.15  	rm -f converter-sample.c
    2.16 +	touch Sync.c
    2.17  
    2.18  clean:
    2.19  	rm -f *.a *.o *.c *.h *.sample sync.asn1 keysync.asn1
     3.1 --- a/src/aux_mime_msg.c	Mon May 06 17:52:20 2019 +0200
     3.2 +++ b/src/aux_mime_msg.c	Mon May 13 19:30:36 2019 +0200
     3.3 @@ -268,5 +268,7 @@
     3.4  
     3.5      return status;
     3.6  }
     3.7 +#else
     3.8 +const int the_answer_my_friend = 42;
     3.9 +#endif
    3.10  
    3.11 -#endif
     4.1 --- a/src/message_api.c	Mon May 06 17:52:20 2019 +0200
     4.2 +++ b/src/message_api.c	Mon May 13 19:30:36 2019 +0200
     4.3 @@ -1484,6 +1484,7 @@
     4.4                          break;
     4.5                      // else fall through and delete    
     4.6                  case PEP_KEY_IMPORTED:
     4.7 +                case PEP_STATUS_OK:
     4.8                      to_delete = bl;
     4.9                      if (prev)
    4.10                          prev->next = bl->next;
    4.11 @@ -3183,7 +3184,7 @@
    4.12          return false;
    4.13      PEP_STATUS status = import_key(session, the_key->value, the_key->size, NULL);
    4.14      free_bloblist(the_key);
    4.15 -    if (status == PEP_KEY_IMPORTED)
    4.16 +    if (status == PEP_STATUS_OK || status == PEP_KEY_IMPORTED)
    4.17          return true;
    4.18      return false;
    4.19  }
     5.1 --- a/src/pgp_sequoia.c	Mon May 06 17:52:20 2019 +0200
     5.2 +++ b/src/pgp_sequoia.c	Mon May 13 19:30:36 2019 +0200
     5.3 @@ -5,8 +5,7 @@
     5.4  
     5.5  #define _GNU_SOURCE 1
     5.6  
     5.7 -#define MAX_PATH 1024
     5.8 -
     5.9 +#include "platform.h"
    5.10  #include "pEp_internal.h"
    5.11  #include "pgp_gpg.h"
    5.12  
    5.13 @@ -48,6 +47,15 @@
    5.14  } while(0)
    5.15  
    5.16  // Verbosely displays errors.
    5.17 +#  define DUMP_STATUS(__de_sq_status, __de_pep_status, ...) do { \
    5.18 +    TC(__VA_ARGS__);                                            \
    5.19 +    _T(": ");                                                   \
    5.20 +    if (__de_sq_status) {                                       \
    5.21 +        _T("Sequoia: %s => ", pgp_status_to_string(__de_sq_status));   \
    5.22 +    }                                                           \
    5.23 +    _T("%s\n", pEp_status_to_string(__de_pep_status));          \
    5.24 +} while(0)
    5.25 +
    5.26  #  define DUMP_ERR(__de_err, __de_status, ...) do {             \
    5.27      TC(__VA_ARGS__);                                            \
    5.28      _T(": ");                                                   \
    5.29 @@ -69,15 +77,75 @@
    5.30      }                                                               \
    5.31  } while(0)
    5.32  
    5.33 +int email_cmp(void *cookie, int a_len, const void *a, int b_len, const void *b)
    5.34 +{
    5.35 +    pgp_packet_t a_userid = pgp_user_id_from_raw (a, a_len);
    5.36 +    pgp_packet_t b_userid = pgp_user_id_from_raw (b, b_len);
    5.37 +
    5.38 +    T("(%.*s, %.*s)", a_len, (const char *) a, b_len, (const char *) b);
    5.39 +
    5.40 +    char *a_address = NULL;
    5.41 +    pgp_user_id_address_normalized(NULL, a_userid, &a_address);
    5.42 +
    5.43 +    char *b_address = NULL;
    5.44 +    pgp_user_id_address_normalized(NULL, b_userid, &b_address);
    5.45 +
    5.46 +    pgp_packet_free(a_userid);
    5.47 +    pgp_packet_free(b_userid);
    5.48 +
    5.49 +    // return an integer that is negative, zero, or positive if the
    5.50 +    // first string is less than, equal to, or greater than the
    5.51 +    // second, respectively.
    5.52 +    int result;
    5.53 +    if (!a_address && !b_address)
    5.54 +        result = 0;
    5.55 +    else if (!a_address)
    5.56 +        result = -1;
    5.57 +    else if (!b_address)
    5.58 +        result = 1;
    5.59 +    else
    5.60 +        result = strcmp(a_address, b_address);
    5.61 +
    5.62 +    if (true) {
    5.63 +        T("'%s' %s '%s'",
    5.64 +          a_address,
    5.65 +          result == 0 ? "==" : result < 0 ? "<" : ">",
    5.66 +          b_address);
    5.67 +    }
    5.68 +
    5.69 +    free(a_address);
    5.70 +    free(b_address);
    5.71 +
    5.72 +    return result;
    5.73 +}
    5.74 +
    5.75  PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
    5.76  {
    5.77 +    #define PATH "/.pEp_keys.db"
    5.78 + 
    5.79      PEP_STATUS status = PEP_STATUS_OK;
    5.80  
    5.81 -    char path[MAX_PATH];
    5.82 -    unix_local_db_file(path, "pEp_keys.db");
    5.83 +    // Create the home directory.
    5.84 +    char *home_env = NULL;
    5.85 +#ifndef NDEBUG
    5.86 +    home_env = getenv("PEP_HOME");
    5.87 +#endif
    5.88 +    if (!home_env)
    5.89 +        home_env = getenv("HOME");
    5.90 +    if (!home_env)
    5.91 +        ERROR_OUT(NULL, PEP_INIT_GPGME_INIT_FAILED, "HOME unset");
    5.92 +
    5.93 +    // Create the DB and initialize it.
    5.94 +    size_t path_size = strlen(home_env) + sizeof(PATH);
    5.95 +    char *path = (char *) calloc(1, path_size);
    5.96 +    assert(path);
    5.97      if (!path)
    5.98 -        ERROR_OUT(NULL, PEP_INIT_GPGME_INIT_FAILED,
    5.99 -                  "could not determine path to keys DB");
   5.100 +        ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   5.101 +
   5.102 +    int r = snprintf(path, path_size, "%s/.pEp_keys.db", home_env);
   5.103 +    assert(r >= 0 && r < path_size);
   5.104 +    if (r < 0)
   5.105 +        ERROR_OUT(NULL, PEP_UNKNOWN_ERROR, "snprintf");
   5.106  
   5.107      int sqlite_result;
   5.108      sqlite_result = sqlite3_open_v2(path,
   5.109 @@ -87,7 +155,7 @@
   5.110                                      | SQLITE_OPEN_FULLMUTEX
   5.111                                      | SQLITE_OPEN_PRIVATECACHE,
   5.112                                      NULL);
   5.113 -
   5.114 +    free(path);
   5.115      if (sqlite_result != SQLITE_OK)
   5.116          ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
   5.117                    "opening keys DB: %s", sqlite3_errmsg(session->key_db));
   5.118 @@ -104,6 +172,17 @@
   5.119  
   5.120      sqlite3_busy_timeout(session->key_db, BUSY_WAIT_TIME);
   5.121  
   5.122 +    sqlite_result =
   5.123 +        sqlite3_create_collation(session->key_db,
   5.124 +                                "EMAIL",
   5.125 +                                SQLITE_UTF8,
   5.126 +                                /* pArg (cookie) */ NULL,
   5.127 +                                email_cmp);
   5.128 +    if (sqlite_result != SQLITE_OK)
   5.129 +        ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
   5.130 +                  "registering EMAIL collation function: %s",
   5.131 +                  sqlite3_errmsg(session->key_db));
   5.132 +
   5.133      sqlite_result = sqlite3_exec(session->key_db,
   5.134                                   "CREATE TABLE IF NOT EXISTS keys (\n"
   5.135                                   "   primary_key TEXT UNIQUE PRIMARY KEY,\n"
   5.136 @@ -137,7 +216,7 @@
   5.137  
   5.138      sqlite_result = sqlite3_exec(session->key_db,
   5.139                                   "CREATE TABLE IF NOT EXISTS userids (\n"
   5.140 -                                 "   userid TEXT NOT NULL,\n"
   5.141 +                                 "   userid TEXT NOT NULL COLLATE EMAIL,\n"
   5.142                                   "   primary_key TEXT NOT NULL,\n"
   5.143                                   "   UNIQUE(userid, primary_key),\n"
   5.144                                   "   FOREIGN KEY (primary_key)\n"
   5.145 @@ -145,7 +224,7 @@
   5.146                                   "     ON DELETE CASCADE\n"
   5.147                                   ");\n"
   5.148                                   "CREATE INDEX IF NOT EXISTS userids_index\n"
   5.149 -                                 "  ON userids (userid, primary_key)\n",
   5.150 +                                 "  ON userids (userid COLLATE EMAIL, primary_key)\n",
   5.151                                   NULL, NULL, NULL);
   5.152      if (sqlite_result != SQLITE_OK)
   5.153          ERROR_OUT(NULL, PEP_INIT_CANNOT_OPEN_DB,
   5.154 @@ -305,59 +384,6 @@
   5.155  
   5.156  */
   5.157  
   5.158 -// Splits an OpenPGP user id into its name and email components.  A
   5.159 -// user id looks like:
   5.160 -//
   5.161 -//   Name (comment) <email>
   5.162 -//
   5.163 -// This function takes ownership of user_id!!!
   5.164 -//
   5.165 -// namep and emailp may be NULL if they are not required.
   5.166 -static void user_id_split(char *, char **, char **) __attribute__((nonnull(1)));
   5.167 -static void user_id_split(char *user_id, char **namep, char **emailp)
   5.168 -{
   5.169 -    if (namep)
   5.170 -        *namep = NULL;
   5.171 -    if (emailp)
   5.172 -        *emailp = NULL;
   5.173 -
   5.174 -    char *email = strchr(user_id, '<');
   5.175 -    if (email) {
   5.176 -        // NUL terminate the string here so that user_id now points at
   5.177 -        // most to: "Name (comment)"
   5.178 -        *email = 0;
   5.179 -
   5.180 -        if (emailp && email[1]) {
   5.181 -            email = email + 1;
   5.182 -            char *end = strchr(email, '>');
   5.183 -            if (end) {
   5.184 -                *end = 0;
   5.185 -                *emailp = strdup(email);
   5.186 -            }
   5.187 -        }
   5.188 -    }
   5.189 -
   5.190 -    if (!namep)
   5.191 -        return;
   5.192 -
   5.193 -    char *comment = strchr(user_id, '(');
   5.194 -    if (comment)
   5.195 -        *comment = 0;
   5.196 -
   5.197 -    // Kill any trailing white space.
   5.198 -    for (size_t l = strlen(user_id); l > 0 && user_id[l - 1] == ' '; l --)
   5.199 -        user_id[l - 1] = 0;
   5.200 -
   5.201 -    // Kill any leading whitespace.
   5.202 -    char *start = user_id;
   5.203 -    while (*start == ' ')
   5.204 -        start ++;
   5.205 -    if (start[0])
   5.206 -        *namep = strdup(start);
   5.207 -
   5.208 -    free(user_id);
   5.209 -}
   5.210 -
   5.211  // step statement and load the tpk and secret.
   5.212  static PEP_STATUS key_load(PEP_SESSION, sqlite3_stmt *, pgp_tpk_t *, int *)
   5.213      __attribute__((nonnull(1, 2)));
   5.214 @@ -607,6 +633,8 @@
   5.215      int tried_commit = 0;
   5.216      pgp_tpk_key_iter_t key_iter = NULL;
   5.217      pgp_user_id_binding_iter_t user_id_iter = NULL;
   5.218 +    char *email = NULL;
   5.219 +    char *name = NULL;
   5.220  
   5.221      sqlite3_stmt *stmt = session->sq_sql.begin_transaction;
   5.222      int sqlite_result = sqlite3_step(stmt);
   5.223 @@ -641,9 +669,9 @@
   5.224          ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "out of memory");
   5.225  
   5.226      pgp_status_t pgp_status;
   5.227 -    pgp_tsk_t tsk = pgp_tpk_into_tsk(tpk);
   5.228 +    pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
   5.229      pgp_status = pgp_tsk_serialize(&err, tsk, writer);
   5.230 -    tpk = pgp_tsk_into_tpk(tsk);
   5.231 +    pgp_tsk_free(tsk);
   5.232      //pgp_writer_free(writer);
   5.233      if (pgp_status != 0)
   5.234          ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Serializing TPK");
   5.235 @@ -692,20 +720,27 @@
   5.236      pgp_user_id_binding_t binding;
   5.237      int first = 1;
   5.238      while ((binding = pgp_user_id_binding_iter_next(user_id_iter))) {
   5.239 -        char *user_id = pgp_user_id_binding_user_id(binding);
   5.240 -        if (!user_id || !*user_id)
   5.241 +        char *user_id_value = pgp_user_id_binding_user_id(binding);
   5.242 +        if (!user_id_value || !*user_id_value)
   5.243              continue;
   5.244  
   5.245          // Ignore bindings with a self-revocation certificate, but no
   5.246          // self-signature.
   5.247          if (!pgp_user_id_binding_selfsig(binding)) {
   5.248 -            free(user_id);
   5.249 +            free(user_id_value);
   5.250              continue;
   5.251          }
   5.252  
   5.253 -        char *name, *email;
   5.254 -        user_id_split(user_id, &name, &email); /* user_id is comsumed.  */
   5.255 -        // XXX: Correctly clean up name and email on error...
   5.256 +        free(name);
   5.257 +        name = NULL;
   5.258 +        free(email);
   5.259 +        email = NULL;
   5.260 +
   5.261 +        pgp_packet_t userid = pgp_user_id_new (user_id_value);
   5.262 +        pgp_user_id_name(NULL, userid, &name);
   5.263 +        pgp_user_id_address(NULL, userid, &email);
   5.264 +        pgp_packet_free(userid);
   5.265 +        free(user_id_value);
   5.266  
   5.267          if (email) {
   5.268              T("  userid: %s", email);
   5.269 @@ -718,7 +753,6 @@
   5.270  
   5.271              if (sqlite_result != SQLITE_DONE) {
   5.272                  pgp_user_id_binding_iter_free(user_id_iter);
   5.273 -                free(name);
   5.274                  ERROR_OUT(NULL, PEP_UNKNOWN_ERROR,
   5.275                            "Updating userids: %s", sqlite3_errmsg(session->key_db));
   5.276              }
   5.277 @@ -736,8 +770,6 @@
   5.278              if (*private_idents == NULL)
   5.279                  ERROR_OUT(NULL, PEP_OUT_OF_MEMORY, "identity_list_add");
   5.280          }
   5.281 -        free(email);
   5.282 -        free(name);
   5.283  
   5.284      }
   5.285      pgp_user_id_binding_iter_free(user_id_iter);
   5.286 @@ -761,6 +793,8 @@
   5.287  
   5.288      T("(%s) -> %s", fpr, pEp_status_to_string(status));
   5.289  
   5.290 +    free(email);
   5.291 +    free(name);
   5.292      if (user_id_iter)
   5.293          pgp_user_id_binding_iter_free(user_id_iter);
   5.294      if (key_iter)
   5.295 @@ -815,10 +849,12 @@
   5.296  }
   5.297  
   5.298  static pgp_status_t
   5.299 -get_secret_keys_cb(void *cookie_opaque,
   5.300 -                   pgp_pkesk_t *pkesks, size_t pkesk_count,
   5.301 -                   pgp_skesk_t *skesks, size_t skesk_count,
   5.302 -                   pgp_secret_t *secret)
   5.303 +decrypt_cb(void *cookie_opaque,
   5.304 +           pgp_pkesk_t *pkesks, size_t pkesk_count,
   5.305 +           pgp_skesk_t *skesks, size_t skesk_count,
   5.306 +           pgp_decryptor_do_decrypt_cb_t *decrypt,
   5.307 +           void *decrypt_cookie,
   5.308 +           pgp_fingerprint_t *identity_out)
   5.309  {
   5.310      pgp_error_t err = NULL;
   5.311      struct decrypt_cookie *cookie = cookie_opaque;
   5.312 @@ -840,6 +876,7 @@
   5.313          pgp_keyid_t keyid = pgp_pkesk_recipient(pkesk); /* Reference. */
   5.314          char *keyid_str = pgp_keyid_to_hex(keyid);
   5.315          pgp_tpk_key_iter_t key_iter = NULL;
   5.316 +        pgp_session_key_t sk = NULL;
   5.317  
   5.318          T("Considering PKESK for %s", keyid_str);
   5.319  
   5.320 @@ -897,12 +934,21 @@
   5.321              goto eol;
   5.322          }
   5.323  
   5.324 +        sk = pgp_session_key_from_bytes (session_key, session_key_len);
   5.325 +        pgp_status_t status;
   5.326 +        if ((status = decrypt (decrypt_cookie, algo, sk))) {
   5.327 +            DUMP_STATUS(status, PEP_UNKNOWN_ERROR, "decrypt_cb");
   5.328 +            goto eol;
   5.329 +        }
   5.330 +
   5.331          T("Decrypted PKESK for %s", keyid_str);
   5.332  
   5.333 -        *secret = pgp_secret_cached(algo, session_key, session_key_len);
   5.334 +        *identity_out = pgp_tpk_fingerprint(tpk);
   5.335          cookie->decrypted = 1;
   5.336  
   5.337      eol:
   5.338 +        if (sk)
   5.339 +            pgp_session_key_free (sk);
   5.340          free(keyid_str);
   5.341          if (key_iter)
   5.342              pgp_tpk_key_iter_free(key_iter);
   5.343 @@ -916,6 +962,7 @@
   5.344          pgp_keyid_t keyid = pgp_pkesk_recipient(pkesk); /* Reference. */
   5.345          char *keyid_str = pgp_keyid_to_hex(keyid);
   5.346          pgp_tpk_key_iter_t key_iter = NULL;
   5.347 +        pgp_session_key_t sk = NULL;
   5.348  
   5.349          if (strcmp(keyid_str, "0000000000000000") != 0)
   5.350              goto eol2;
   5.351 @@ -961,8 +1008,17 @@
   5.352                  free(fp_string);
   5.353                  pgp_fingerprint_free(fp);
   5.354  
   5.355 -                *secret = pgp_secret_cached(algo, session_key, session_key_len);
   5.356 +                pgp_session_key_t sk = pgp_session_key_from_bytes (session_key,
   5.357 +                                                                   session_key_len);
   5.358 +                pgp_status_t status;
   5.359 +                if ((status = decrypt (decrypt_cookie, algo, sk))) {
   5.360 +                    DUMP_STATUS(status, PEP_UNKNOWN_ERROR, "decrypt_cb");
   5.361 +                    goto eol2;
   5.362 +                }
   5.363 +
   5.364 +                *identity_out = pgp_tpk_fingerprint(tsk);
   5.365                  cookie->decrypted = 1;
   5.366 +
   5.367                  break;
   5.368              }
   5.369  
   5.370 @@ -970,6 +1026,8 @@
   5.371              key_iter = NULL;
   5.372          }
   5.373      eol2:
   5.374 +        if (sk)
   5.375 +            pgp_session_key_free (sk);
   5.376          free(keyid_str);
   5.377          if (key_iter)
   5.378              pgp_tpk_key_iter_free(key_iter);
   5.379 @@ -985,85 +1043,145 @@
   5.380  }
   5.381  
   5.382  static pgp_status_t
   5.383 -check_signatures_cb(void *cookie_opaque,
   5.384 -                   pgp_verification_results_t results, size_t levels)
   5.385 +check_signatures_cb(void *cookie_opaque, pgp_message_structure_t structure)
   5.386  {
   5.387      struct decrypt_cookie *cookie = cookie_opaque;
   5.388      PEP_SESSION session = cookie->session;
   5.389  
   5.390 -    int level;
   5.391 -    for (level = 0; level < levels; level ++) {
   5.392 -        pgp_verification_result_t *vrs;
   5.393 -        size_t vr_count;
   5.394 -        pgp_verification_results_at_level(results, level, &vrs, &vr_count);
   5.395 +    pgp_message_structure_iter_t iter
   5.396 +        = pgp_message_structure_iter (structure);
   5.397 +    for (pgp_message_layer_t layer = pgp_message_structure_iter_next (iter);
   5.398 +         layer;
   5.399 +         layer = pgp_message_structure_iter_next (iter)) {
   5.400 +        pgp_verification_result_iter_t results;
   5.401  
   5.402 -        int i;
   5.403 -        for (i = 0; i < vr_count; i ++) {
   5.404 -            pgp_tpk_t tpk = NULL;
   5.405 -            pgp_verification_result_code_t code
   5.406 -                = pgp_verification_result_code(vrs[i]);
   5.407 +        switch (pgp_message_layer_variant (layer)) {
   5.408 +        case PGP_MESSAGE_LAYER_COMPRESSION:
   5.409 +        case PGP_MESSAGE_LAYER_ENCRYPTION:
   5.410 +            break;
   5.411  
   5.412 -            if (code == PGP_VERIFICATION_RESULT_CODE_BAD_CHECKSUM) {
   5.413 -                cookie->bad_checksums ++;
   5.414 -                continue;
   5.415 +        case PGP_MESSAGE_LAYER_SIGNATURE_GROUP:
   5.416 +            pgp_message_layer_signature_group(layer, &results);
   5.417 +            pgp_verification_result_t result;
   5.418 +            while ((result = pgp_verification_result_iter_next (results))) {
   5.419 +                pgp_signature_t sig;
   5.420 +                pgp_keyid_t keyid = NULL;
   5.421 +                char *keyid_str = NULL;
   5.422 +
   5.423 +                switch (pgp_verification_result_variant (result)) {
   5.424 +                case PGP_VERIFICATION_RESULT_GOOD_CHECKSUM:
   5.425 +                    // We need to add the fingerprint of the primary
   5.426 +                    // key to cookie->signer_keylist.
   5.427 +
   5.428 +                    pgp_verification_result_good_checksum (result, &sig, NULL,
   5.429 +                                                           NULL, NULL, NULL);
   5.430 +
   5.431 +                    // First try looking up by the TPK using the
   5.432 +                    // IssuerFingerprint subpacket.
   5.433 +                    pgp_fingerprint_t fpr
   5.434 +                        = pgp_signature_issuer_fingerprint(sig);
   5.435 +                    if (fpr) {
   5.436 +                        // Even though we have a fingerprint, we have
   5.437 +                        // to look the key up by keyid, because we
   5.438 +                        // want to match on subkeys and we only store
   5.439 +                        // keyids for subkeys.
   5.440 +                        keyid = pgp_fingerprint_to_keyid(fpr);
   5.441 +                        pgp_fingerprint_free(fpr);
   5.442 +                    } else {
   5.443 +                        // That is not available, try using the Issuer
   5.444 +                        // subpacket.
   5.445 +                        keyid = pgp_signature_issuer(sig);
   5.446 +                    }
   5.447 +
   5.448 +                    if (! keyid) {
   5.449 +                        T("signature with no Issuer or Issuer Fingerprint subpacket!");
   5.450 +                        goto eol;
   5.451 +                    }
   5.452 +
   5.453 +                    pgp_tpk_t tpk;
   5.454 +                    if (tpk_find_by_keyid(session, keyid, false,
   5.455 +                                          &tpk, NULL) != PEP_STATUS_OK)
   5.456 +                        ; // Soft error.  Ignore.
   5.457 +
   5.458 +                    if (tpk) {
   5.459 +                        // Ok, we have a TPK.
   5.460 +
   5.461 +                        // We need the primary key's fingerprint (not
   5.462 +                        // the issuer fingerprint).
   5.463 +                        pgp_fingerprint_t primary_fpr
   5.464 +                            = pgp_tpk_fingerprint(tpk);
   5.465 +                        char *primary_fpr_str
   5.466 +                            = pgp_fingerprint_to_hex(primary_fpr);
   5.467 +                        stringlist_add_unique(cookie->signer_keylist,
   5.468 +                                              primary_fpr_str);
   5.469 +
   5.470 +                        T("Good signature from %s", primary_fpr_str);
   5.471 +
   5.472 +                        // XXX: Check that the TPK and the key used to make
   5.473 +                        // the signature and the signature itself are alive
   5.474 +                        // and not revoked.  Revoked =>
   5.475 +                        // PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH; Expired key
   5.476 +                        // or sig => PEP_DECRYPTED.
   5.477 +                        cookie->good_checksums ++;
   5.478 +
   5.479 +                        free(primary_fpr_str);
   5.480 +                        pgp_fingerprint_free(primary_fpr);
   5.481 +                        pgp_tpk_free(tpk);
   5.482 +                    } else {
   5.483 +                        // If we get
   5.484 +                        // PGP_VERIFICATION_RESULT_CODE_GOOD_CHECKSUM, then the
   5.485 +                        // TPK should be available.  But, another process
   5.486 +                        // could have deleted the key from the store in the
   5.487 +                        // mean time, so be tolerant.
   5.488 +                        T("Key to check signature from %s disappeared",
   5.489 +                          keyid_str);
   5.490 +                        cookie->missing_keys ++;
   5.491 +                    }
   5.492 +                    break;
   5.493 +
   5.494 +                case PGP_VERIFICATION_RESULT_MISSING_KEY:
   5.495 +                    pgp_verification_result_missing_key (result, &sig);
   5.496 +                    keyid = pgp_signature_issuer (sig);
   5.497 +                    keyid_str = pgp_keyid_to_string (keyid);
   5.498 +                    T("No key to check signature from %s", keyid_str);
   5.499 +
   5.500 +                    cookie->missing_keys ++;
   5.501 +                    break;
   5.502 +
   5.503 +                case PGP_VERIFICATION_RESULT_BAD_CHECKSUM:
   5.504 +                    pgp_verification_result_bad_checksum (result, &sig);
   5.505 +                    keyid = pgp_signature_issuer (sig);
   5.506 +                    if (keyid) {
   5.507 +                        keyid_str = pgp_keyid_to_string (keyid);
   5.508 +                        T("Bad signature from %s", keyid_str);
   5.509 +                    } else {
   5.510 +                        T("Bad signature without issuer information");
   5.511 +                    }
   5.512 +
   5.513 +                    cookie->bad_checksums ++;
   5.514 +                    break;
   5.515 +
   5.516 +                default:
   5.517 +                    assert (! "reachable");
   5.518 +                }
   5.519 +
   5.520 +            eol:
   5.521 +                free (keyid_str);
   5.522 +                pgp_signature_free (sig);
   5.523 +                pgp_verification_result_free (result);
   5.524              }
   5.525 -            if (code == PGP_VERIFICATION_RESULT_CODE_MISSING_KEY) {
   5.526 -                // No key, nothing we can do.
   5.527 -                cookie->missing_keys ++;
   5.528 -                continue;
   5.529 -            }
   5.530 +            pgp_verification_result_iter_free (results);
   5.531 +            break;
   5.532  
   5.533 -            // We need to add the fingerprint of the primary key to
   5.534 -            // cookie->signer_keylist.
   5.535 -            pgp_signature_t sig = pgp_verification_result_signature(vrs[i]);
   5.536 +        default:
   5.537 +            assert (! "reachable");
   5.538 +        }
   5.539  
   5.540 -            // First try looking up by the TPK using the
   5.541 -            // IssuerFingerprint subpacket.
   5.542 -            pgp_fingerprint_t issuer_fp = pgp_signature_issuer_fingerprint(sig);
   5.543 -            if (issuer_fp) {
   5.544 -                pgp_keyid_t issuer = pgp_fingerprint_to_keyid(issuer_fp);
   5.545 -                if (tpk_find_by_keyid(session, issuer, false, &tpk, NULL) != PEP_STATUS_OK)
   5.546 -                    ; // Soft error.  Ignore.
   5.547 -                pgp_keyid_free(issuer);
   5.548 -                pgp_fingerprint_free(issuer_fp);
   5.549 -            }
   5.550 +        pgp_message_layer_free (layer);
   5.551 +    }
   5.552  
   5.553 -            // If that is not available, try using the Issuer subpacket.
   5.554 -            if (!tpk) {
   5.555 -                pgp_keyid_t issuer = pgp_signature_issuer(sig);
   5.556 -                if (issuer) {
   5.557 -                    if (tpk_find_by_keyid(session, issuer, false, &tpk, NULL) != PEP_STATUS_OK)
   5.558 -                        ; // Soft error.  Ignore.
   5.559 -                }
   5.560 -                pgp_keyid_free(issuer);
   5.561 -            }
   5.562 -
   5.563 -            if (tpk) {
   5.564 -                // Ok, we have a TPK.
   5.565 -                pgp_fingerprint_t fp = pgp_tpk_fingerprint(tpk);
   5.566 -                char *fp_str = pgp_fingerprint_to_hex(fp);
   5.567 -                stringlist_add_unique(cookie->signer_keylist, fp_str);
   5.568 -
   5.569 -                // XXX: Check that the TPK and the key used to make
   5.570 -                // the signature and the signature itself are alive
   5.571 -                // and not revoked.  Revoked =>
   5.572 -                // PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH; Expired key
   5.573 -                // or sig => PEP_DECRYPTED.
   5.574 -                cookie->good_checksums ++;
   5.575 -
   5.576 -                free(fp_str);
   5.577 -                pgp_fingerprint_free(fp);
   5.578 -                pgp_tpk_free(tpk);
   5.579 -            } else {
   5.580 -                // If we get
   5.581 -                // PGP_VERIFICATION_RESULT_CODE_GOOD_CHECKSUM, then the
   5.582 -                // TPK should be available.  But, another process
   5.583 -                // could have deleted the key from the store in the
   5.584 -                // mean time, so be tolerant.
   5.585 -                cookie->missing_keys ++;
   5.586 -            }
   5.587 -        }
   5.588 -    }
   5.589 +    pgp_message_structure_iter_free (iter);
   5.590 +    pgp_message_structure_free (structure);
   5.591  
   5.592      return PGP_STATUS_SUCCESS;
   5.593  }
   5.594 @@ -1104,8 +1222,8 @@
   5.595  
   5.596      pgp_error_t err = NULL;
   5.597      decryptor = pgp_decryptor_new(&err, reader,
   5.598 -                                  get_public_keys_cb, get_secret_keys_cb,
   5.599 -                                  check_signatures_cb, &cookie);
   5.600 +                                  get_public_keys_cb, decrypt_cb,
   5.601 +                                  check_signatures_cb, &cookie, 0);
   5.602      if (! decryptor)
   5.603          ERROR_OUT(err, PEP_DECRYPT_NO_KEY, "pgp_decryptor_new");
   5.604  
   5.605 @@ -1202,12 +1320,12 @@
   5.606          verifier = pgp_detached_verifier_new(&err, dsig_reader, reader,
   5.607                                               get_public_keys_cb,
   5.608                                               check_signatures_cb,
   5.609 -                                             &cookie);
   5.610 +                                             &cookie, 0);
   5.611      else
   5.612          verifier = pgp_verifier_new(&err, reader,
   5.613                                      get_public_keys_cb,
   5.614                                      check_signatures_cb,
   5.615 -                                    &cookie);
   5.616 +                                    &cookie, 0);
   5.617      if (! verifier)
   5.618          ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Creating verifier");
   5.619      if (pgp_reader_discard(&err, verifier) < 0)
   5.620 @@ -1515,16 +1633,15 @@
   5.621      T("(%s)", userid);
   5.622  
   5.623      // Generate a key.
   5.624 -    pgp_tsk_t tsk;
   5.625 +    pgp_tpk_builder_t tpkb = pgp_tpk_builder_general_purpose
   5.626 +        (PGP_TPK_CIPHER_SUITE_RSA3K, userid);
   5.627      pgp_signature_t rev;
   5.628 -    if (pgp_tsk_new(&err, userid, &tsk, &rev) != 0)
   5.629 +    if (pgp_tpk_builder_generate(&err, tpkb, &tpk, &rev))
   5.630          ERROR_OUT(err, PEP_CANNOT_CREATE_KEY, "Generating a key pair");
   5.631  
   5.632      // XXX: We should return this.
   5.633      pgp_signature_free(rev);
   5.634  
   5.635 -    tpk = pgp_tsk_into_tpk(tsk);
   5.636 -
   5.637      // Get the fingerprint.
   5.638      pgp_fpr = pgp_tpk_fingerprint(tpk);
   5.639      fpr = pgp_fingerprint_to_hex(pgp_fpr);
   5.640 @@ -1586,14 +1703,13 @@
   5.641      return PEP_STATUS_OK;
   5.642  }
   5.643  
   5.644 -// XXX: This needs to handle not only TPKs, but also keyrings and
   5.645 -// revocation certificates.  Right now, we only import a single TPK
   5.646 -// and ignore everything else.
   5.647 +// XXX: This also needs to handle revocation certificates.
   5.648  PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
   5.649                                size_t size, identity_list **private_idents)
   5.650  {
   5.651 -    PEP_STATUS status = PEP_STATUS_OK;
   5.652 +    PEP_STATUS status = PEP_NO_KEY_IMPORTED;
   5.653      pgp_error_t err;
   5.654 +    pgp_tpk_parser_t parser = NULL;
   5.655  
   5.656      if (private_idents)
   5.657          *private_idents = NULL;
   5.658 @@ -1607,24 +1723,93 @@
   5.659  
   5.660      pgp_tag_t tag = pgp_packet_parser_result_tag(ppr);
   5.661      switch (tag) {
   5.662 -    case PGP_TAG_SIGNATURE:
   5.663 -        // XXX: Implement me.
   5.664 -        // assert(!"Have possible revocation certificate!");
   5.665 -		ERROR_OUT(NULL, PEP_NO_KEY_IMPORTED, "Implement me: Have possible revocation certificate!");
   5.666 +    case PGP_TAG_SIGNATURE: {
   5.667 +        // The following asserts can't fail, because
   5.668 +        // pgp_packet_parser_result_tag succeeded and the tag is
   5.669 +        // right.
   5.670 +        pgp_packet_parser_t pp = pgp_packet_parser_result_packet_parser (ppr);
   5.671 +        assert(pp);
   5.672 +
   5.673 +        pgp_packet_t packet = NULL;
   5.674 +        if (pgp_packet_parser_next(&err, pp, &packet, &ppr))
   5.675 +            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Getting signature packet");
   5.676 +
   5.677 +        pgp_signature_t sig = pgp_packet_ref_signature (packet);
   5.678 +        assert(sig);
   5.679 +
   5.680 +        pgp_tpk_t tpk = NULL;
   5.681 +
   5.682 +        pgp_fingerprint_t issuer_fpr = pgp_signature_issuer_fingerprint(sig);
   5.683 +        if (issuer_fpr) {
   5.684 +            char *issuer_fpr_hex = pgp_fingerprint_to_hex(issuer_fpr);
   5.685 +            T("Importing a signature issued by %s", issuer_fpr_hex);
   5.686 +
   5.687 +            status = tpk_find_by_fpr_hex(session, issuer_fpr_hex,
   5.688 +                                         false, &tpk, NULL);
   5.689 +            if (status && status != PEP_KEY_NOT_FOUND)
   5.690 +                DUMP_ERR(NULL, status, "Looking up %s", issuer_fpr_hex);
   5.691 +
   5.692 +            free(issuer_fpr_hex);
   5.693 +            pgp_fingerprint_free(issuer_fpr);
   5.694 +        }
   5.695 +
   5.696 +        if (! tpk) {
   5.697 +            pgp_keyid_t issuer = pgp_signature_issuer(sig);
   5.698 +            if (issuer) {
   5.699 +                char *issuer_hex = pgp_keyid_to_hex(issuer);
   5.700 +                T("Importing a signature issued by %s", issuer_hex);
   5.701 +
   5.702 +                status = tpk_find_by_keyid_hex(session, issuer_hex,
   5.703 +                                               false, &tpk, NULL);
   5.704 +                if (status && status != PEP_KEY_NOT_FOUND)
   5.705 +                    DUMP_ERR(NULL, status, "Looking up %s", issuer_hex);
   5.706 +
   5.707 +                free(issuer_hex);
   5.708 +                pgp_keyid_free(issuer);
   5.709 +            }
   5.710 +        }
   5.711 +
   5.712 +        // We need a packet.  sig is only a reference, so we just need
   5.713 +        // to free it.
   5.714 +        pgp_signature_free(sig);
   5.715 +
   5.716 +        if (tpk) {
   5.717 +            T("Merging packet: %s", pgp_packet_debug(packet));
   5.718 +
   5.719 +            tpk = pgp_tpk_merge_packets (&err, tpk, &packet, 1);
   5.720 +            if (! tpk)
   5.721 +                ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Merging signature");
   5.722 +
   5.723 +            status = tpk_save(session, tpk, NULL);
   5.724 +            if (status)
   5.725 +                ERROR_OUT(NULL, status, "saving merged TPK");
   5.726 +            status = PEP_KEY_IMPORTED;
   5.727 +        }
   5.728          break;
   5.729 -
   5.730 +    }
   5.731      case PGP_TAG_PUBLIC_KEY:
   5.732      case PGP_TAG_SECRET_KEY: {
   5.733 -        pgp_tpk_t tpk = pgp_tpk_from_packet_parser(&err, ppr);
   5.734 -        if (! tpk)
   5.735 +        parser = pgp_tpk_parser_from_packet_parser(ppr);
   5.736 +        pgp_tpk_t tpk;
   5.737 +        int count = 0;
   5.738 +        err = NULL;
   5.739 +        while ((tpk = pgp_tpk_parser_next(&err, parser))) {
   5.740 +            count ++;
   5.741 +
   5.742 +            T("#%d. TPK for %s, %s",
   5.743 +              count, pgp_tpk_primary_user_id(tpk),
   5.744 +              pgp_fingerprint_to_hex(pgp_tpk_fingerprint(tpk)));
   5.745 +
   5.746 +            // If private_idents is not NULL and there is any private key
   5.747 +            // material, it will be saved.
   5.748 +            status = tpk_save(session, tpk, private_idents);
   5.749 +            if (status == PEP_STATUS_OK)
   5.750 +                status = PEP_KEY_IMPORTED;
   5.751 +            else
   5.752 +                ERROR_OUT(NULL, status, "saving TPK");
   5.753 +        }
   5.754 +        if (err || count == 0)
   5.755              ERROR_OUT(err, PEP_UNKNOWN_ERROR, "parsing key data");
   5.756 -
   5.757 -        // If private_idents is not NULL and there is any private key
   5.758 -        // material, it will be saved.
   5.759 -        status = tpk_save(session, tpk, private_idents);
   5.760 -        if (status == PEP_STATUS_OK)
   5.761 -            status = PEP_KEY_IMPORTED;
   5.762 -        ERROR_OUT(NULL, status, "saving TPK");
   5.763          break;
   5.764      }
   5.765      default:
   5.766 @@ -1634,6 +1819,9 @@
   5.767      }
   5.768  
   5.769   out:
   5.770 +    if (parser)
   5.771 +        pgp_tpk_parser_free(parser);
   5.772 +
   5.773      T("-> %s", pEp_status_to_string(status));
   5.774      return status;
   5.775  }
   5.776 @@ -1673,10 +1861,10 @@
   5.777      }
   5.778  
   5.779      if (secret) {
   5.780 -        pgp_tsk_t tsk = pgp_tpk_into_tsk(tpk);
   5.781 +        pgp_tsk_t tsk = pgp_tpk_as_tsk(tpk);
   5.782          if (pgp_tsk_serialize(&err, tsk, armor_writer))
   5.783              ERROR_OUT(err, PEP_UNKNOWN_ERROR, "serializing TSK");
   5.784 -        tpk = pgp_tsk_into_tpk(tsk);
   5.785 +        pgp_tsk_free(tsk);
   5.786      } else {
   5.787          if (pgp_tpk_serialize(&err, tpk, armor_writer))
   5.788              ERROR_OUT(err, PEP_UNKNOWN_ERROR, "serializing TPK");
     6.1 --- a/src/platform_unix.c	Mon May 06 17:52:20 2019 +0200
     6.2 +++ b/src/platform_unix.c	Mon May 13 19:30:36 2019 +0200
     6.3 @@ -17,21 +17,14 @@
     6.4  #include <sys/types.h>
     6.5  #include <fcntl.h>
     6.6  #include <regex.h>
     6.7 -// #include <stdio.h>
     6.8  
     6.9  #include "platform_unix.h"
    6.10  
    6.11  #define MAX_PATH 1024
    6.12  #ifndef LOCAL_DB_FILENAME
    6.13 -#define LOCAL_DB_FILENAME "pEp_management.db"  /* dot (hidden file) now added in *_local_db() */
    6.14 -#endif
    6.15 -#ifndef LOCAL_KEYS_DB_FILENAME
    6.16 -#define LOCAL_KEYS_DB_FILENAME "pEp_keys.db"
    6.17 +#define LOCAL_DB_FILENAME ".pEp_management.db"
    6.18  #endif
    6.19  #define SYSTEM_DB_FILENAME "system.db"
    6.20 -#ifndef SYSTEM_DB_PREFIX
    6.21 -#define SYSTEM_DB_PREFIX "/usr/local/share/pEp"
    6.22 -#endif
    6.23  
    6.24  #ifndef bool
    6.25  #define bool int
    6.26 @@ -176,58 +169,6 @@
    6.27  
    6.28  #endif
    6.29  
    6.30 -#ifdef NDEBUG
    6.31 -const char *unix_system_db(void)
    6.32 -#else
    6.33 -const char *unix_system_db(int reset)
    6.34 -#endif
    6.35 -{
    6.36 -    static char buffer[MAX_PATH];
    6.37 -    static bool done = false;
    6.38 -
    6.39 -    #ifdef NDEBUG
    6.40 -    if (!done)
    6.41 -    #else
    6.42 -    if ((!done) || reset)
    6.43 -    #endif
    6.44 -    {
    6.45 -        const char *home_env;
    6.46 -        const char *subdir;
    6.47 -        /* TODO: ugly data layout, maybe switch to nested struct */
    6.48 -        const char * const confvars[] = { "TRUSTWORDS", "PEPHOME", "XDG_CONFIG_DIR", NULL,             "HOME",  NULL };
    6.49 -        const char * const confvals[] = { NULL,         NULL,      NULL,             SYSTEM_DB_PREFIX, NULL,    NULL };
    6.50 -        const char * const confsdir[] = { "",           "",        "/pEp",           "",               "/.pEp", NULL };
    6.51 -        const bool confisimportant[] =  { true,         false,     false,            false,            false,   false };
    6.52 -        int cf_i;
    6.53 -        for (cf_i = 0; confvars[cf_i] || confvals[cf_i]; cf_i++) {
    6.54 -            if (((home_env = confvals[cf_i]) || (home_env = getenv (confvars[cf_i]))) && (subdir = confsdir[cf_i])) {
    6.55 -                // printf("unix_system_db (%s) [%s] %s\n", SYSTEM_DB_FILENAME, confvars[cf_i], home_env);
    6.56 -                char *p = stpncpy (buffer, home_env, MAX_PATH);
    6.57 -                ssize_t len = MAX_PATH - (p - buffer) - 2;
    6.58 -
    6.59 -                if (len < strlen (SYSTEM_DB_FILENAME) + strlen (confsdir[cf_i])) {
    6.60 -                    assert(0);
    6.61 -                    return NULL;
    6.62 -                }
    6.63 -
    6.64 -                p = stpncpy(p, confsdir[cf_i], len);
    6.65 -                *p++ = '/';
    6.66 -                strncpy(p, SYSTEM_DB_FILENAME, len);
    6.67 -                // printf("unix_system_db (%s) [%s] -> %s\n", SYSTEM_DB_FILENAME, confvars[cf_i], buffer);
    6.68 -                if (access (buffer, R_OK) == 0) {
    6.69 -                    done = true;
    6.70 -                    return buffer;
    6.71 -                }
    6.72 -                else if (confisimportant[cf_i])
    6.73 -                    return NULL;
    6.74 -            }
    6.75 -            // printf("unix_system_db (%s) %s failed\n", SYSTEM_DB_FILENAME, confvars[cf_i]);
    6.76 -        }
    6.77 -        return NULL;
    6.78 -    }
    6.79 -    return buffer;
    6.80 -}
    6.81 -
    6.82  #if !defined(BSD) && !defined(__APPLE__)
    6.83  
    6.84  size_t strlcpy(char* dst, const	char* src, size_t size) {
    6.85 @@ -268,45 +209,6 @@
    6.86  #endif
    6.87  
    6.88  #ifdef NDEBUG
    6.89 -int unix_local_db_file(char *buffer, const char *fname)
    6.90 -#else
    6.91 -int unix_local_db_file(char *buffer, const char *fname, int reset)
    6.92 -#endif
    6.93 -{
    6.94 -    const char *home_env;
    6.95 -    const char *subdir;
    6.96 -    /* TODO: ugly data layout, maybe switch to nested struct */
    6.97 -    /* Note: in HOME, a dot is prepended to the file (~/.pEp_management.db, vs ~/.pEp/pEp_management.db) */
    6.98 -    const char * const confvars[] = { "PEPHOME", "XDG_CONFIG_DIR", "HOME",  "HOME",   NULL };
    6.99 -    const char * const confvals[] = { NULL,      NULL,             NULL,    NULL,     NULL };
   6.100 -    const char * const confsdir[] = { "/",       "/pEp/",          "/.",    "/.pEp/", NULL };
   6.101 -    const bool confisimportant[] =  { true,      false,            false,   true,     false };
   6.102 -    int cf_i;
   6.103 -
   6.104 -    for (cf_i = 0; confvars[cf_i] || confvals[cf_i]; cf_i++) {
   6.105 -        if (((home_env = confvals[cf_i]) || (home_env = getenv (confvars[cf_i]))) && (subdir = confsdir[cf_i])) {
   6.106 -            // printf("unix_local_db_file(%s) [%s] %s\n", fname, confvars[cf_i], home_env);
   6.107 -            char *p = stpncpy (buffer, home_env, MAX_PATH);
   6.108 -            ssize_t len = MAX_PATH - (p - buffer) - 1;
   6.109 -
   6.110 -            if (len < strlen (fname) + strlen (confsdir[cf_i])) {
   6.111 -                assert(0);
   6.112 -                return false;
   6.113 -            }
   6.114 -
   6.115 -            p = stpncpy(p, confsdir[cf_i], len);
   6.116 -            strncpy(p, fname, len);
   6.117 -            // printf("unix_local_db_file(%s) [%s] -> %s\n", fname, confvars[cf_i], buffer);
   6.118 -            if (confisimportant[cf_i] || (access (buffer, R_OK) == 0)) {
   6.119 -                return true;
   6.120 -            }
   6.121 -        }
   6.122 -        // printf("unix_local_db_file(%s) %s failed\n", fname, confvars[cf_i]);
   6.123 -    }
   6.124 -    return false;
   6.125 -}
   6.126 -
   6.127 -#ifdef NDEBUG
   6.128  const char *unix_local_db(void)
   6.129  #else
   6.130  const char *unix_local_db(int reset)
   6.131 @@ -317,41 +219,31 @@
   6.132  
   6.133      #ifdef NDEBUG
   6.134      if (!done)
   6.135 -        done = unix_local_db_file(buffer, LOCAL_DB_FILENAME);
   6.136      #else
   6.137      if ((!done) || reset)
   6.138 -        done = unix_local_db_file(buffer, LOCAL_DB_FILENAME, reset);
   6.139      #endif
   6.140 +    {
   6.141 +        char *home_env;
   6.142 +        if((home_env = getenv("HOME"))){
   6.143 +            char *p = stpncpy(buffer, home_env, MAX_PATH);
   6.144 +            ssize_t len = MAX_PATH - (p - buffer) - 2;
   6.145  
   6.146 -    if (done)
   6.147 -        return buffer;
   6.148 -    return NULL;
   6.149 +            if (len < strlen(LOCAL_DB_FILENAME)) {
   6.150 +                assert(0);
   6.151 +                return NULL;
   6.152 +            }
   6.153 +
   6.154 +            *p++ = '/';
   6.155 +            strncpy(p, LOCAL_DB_FILENAME, len);
   6.156 +            done = true;
   6.157 +        }else{
   6.158 +            return NULL;
   6.159 +        }
   6.160 +
   6.161 +    }
   6.162 +    return buffer;
   6.163  }
   6.164  
   6.165 -#ifdef NDEBUG
   6.166 -const char *unix_local_keys_db(void)
   6.167 -#else
   6.168 -const char *unix_local_keys_db(int reset)
   6.169 -#endif
   6.170 -{
   6.171 -    static char buffer[MAX_PATH];
   6.172 -    static bool done = false;
   6.173 -
   6.174 -    #ifdef NDEBUG
   6.175 -    if (!done)
   6.176 -        done = unix_local_db_file(buffer, LOCAL_KEYS_DB_FILENAME);
   6.177 -    #else
   6.178 -    if ((!done) || reset)
   6.179 -        done = unix_local_db_file(buffer, LOCAL_KEYS_DB_FILENAME, reset);
   6.180 -    #endif
   6.181 -
   6.182 -    if (done) {
   6.183 -        return buffer;
   6.184 -    }
   6.185 -    return NULL;
   6.186 -}
   6.187 -
   6.188 -
   6.189  static const char *gpg_conf_path = ".gnupg";
   6.190  static const char *gpg_conf_name = "gpg.conf";
   6.191  static const char *gpg_agent_conf_name = "gpg-agent.conf";
     7.1 --- a/src/status_to_string.h	Mon May 06 17:52:20 2019 +0200
     7.2 +++ b/src/status_to_string.h	Mon May 13 19:30:36 2019 +0200
     7.3 @@ -4,7 +4,7 @@
     7.4  extern "C" {
     7.5  #endif
     7.6  
     7.7 -inline const char *pEp_status_to_string(PEP_STATUS status) {
     7.8 +static inline const char *pEp_status_to_string(PEP_STATUS status) {
     7.9      switch (status) {
    7.10      case PEP_STATUS_OK: return "PEP_STATUS_OK";
    7.11  
     8.1 --- a/sync/gen_statemachine.ysl2	Mon May 06 17:52:20 2019 +0200
     8.2 +++ b/sync/gen_statemachine.ysl2	Mon May 13 19:30:36 2019 +0200
     8.3 @@ -656,7 +656,9 @@
     8.4                                  status = PEP_OUT_OF_MEMORY;
     8.5                                  goto the_end;
     8.6                              }
     8.7 -                            key_data_size = 1;
     8.8 +                            key_data_size = 1; // N.B. If null termination makes us happy for debugging, fine, but 
     8.9 +                                               // if we include this in the size, libetpan will null terminate and 
    8.10 +                                               // go bananas. We can't have a NUL in the mime text.
    8.11  
    8.12                              for (stringlist_t *sl = session->own_«yml:lcase(@name)»_state.own_keys;
    8.13                                      sl && sl->value ; sl = sl->next)
    8.14 @@ -711,7 +713,8 @@
    8.15  
    8.16                              // add secret key data as attachment
    8.17  
    8.18 -                            bloblist_t *bl = bloblist_add(_m->attachments, key_data, key_data_size,
    8.19 +                            // N.B. The -1 makes sure we do NOT add a NUL into the mime stream!
    8.20 +                            bloblist_t *bl = bloblist_add(_m->attachments, key_data, key_data_size - 1,
    8.21                                      "application/octet-stream", "file://own.key");
    8.22                              if (!bl) {
    8.23                                  free(_data);
     9.1 --- a/sync/sync.fsm	Mon May 06 17:52:20 2019 +0200
     9.2 +++ b/sync/sync.fsm	Mon May 13 19:30:36 2019 +0200
     9.3 @@ -10,7 +10,7 @@
     9.4  protocol Sync 1 {
     9.5      // all messages have a timestamp, time out and are removed after timeout
     9.6  
     9.7 -    fsm KeySync 1, threshold=30 {
     9.8 +    fsm KeySync 1, threshold=60 {
     9.9          version 1, 2;
    9.10  
    9.11          state InitState {
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/include/KeyringImportTests.h	Mon May 13 19:30:36 2019 +0200
    10.3 @@ -0,0 +1,23 @@
    10.4 +// This file is under GNU General Public License 3.0
    10.5 +// see LICENSE.txt
    10.6 +
    10.7 +#ifndef KEYRING_IMPORT_TESTS_H
    10.8 +#define KEYRING_IMPORT_TESTS_H
    10.9 +
   10.10 +#include <string>
   10.11 +#include "EngineTestSessionSuite.h"
   10.12 +
   10.13 +using namespace std;
   10.14 +
   10.15 +class KeyringImportTests : public EngineTestSessionSuite {
   10.16 +    public:
   10.17 +        KeyringImportTests(string test_suite, string test_home_dir);
   10.18 +	protected:
   10.19 +        void setup();
   10.20 +        void tear_down();
   10.21 +    private:
   10.22 +        void import1();
   10.23 +        void import2();
   10.24 +};
   10.25 +
   10.26 +#endif
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/include/LookupTests.h	Mon May 13 19:30:36 2019 +0200
    11.3 @@ -0,0 +1,22 @@
    11.4 +// This file is under GNU General Public License 3.0
    11.5 +// see LICENSE.txt
    11.6 +
    11.7 +#ifndef LOOKUP_H
    11.8 +#define LOOKUP_H
    11.9 +
   11.10 +#include <string>
   11.11 +#include "EngineTestSessionSuite.h"
   11.12 +
   11.13 +using namespace std;
   11.14 +
   11.15 +class LookupTests : public EngineTestSessionSuite {
   11.16 +    public:
   11.17 +        LookupTests(string test_suite, string test_home_dir);
   11.18 +	protected:
   11.19 +        void setup();
   11.20 +        void tear_down();
   11.21 +    private:
   11.22 +        void lookup();
   11.23 +};
   11.24 +
   11.25 +#endif
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/include/RevocationTests.h	Mon May 13 19:30:36 2019 +0200
    12.3 @@ -0,0 +1,22 @@
    12.4 +// This file is under GNU General Public License 3.0
    12.5 +// see LICENSE.txt
    12.6 +
    12.7 +#ifndef REVOCATION_H
    12.8 +#define REVOCATION_H
    12.9 +
   12.10 +#include <string>
   12.11 +#include "EngineTestSessionSuite.h"
   12.12 +
   12.13 +using namespace std;
   12.14 +
   12.15 +class RevocationTests : public EngineTestSessionSuite {
   12.16 +    public:
   12.17 +        RevocationTests(string test_suite, string test_home_dir);
   12.18 +	protected:
   12.19 +        void setup();
   12.20 +        void tear_down();
   12.21 +    private:
   12.22 +        void revocation();
   12.23 +};
   12.24 +
   12.25 +#endif
    13.1 --- a/test/src/SuiteMaker.cc	Mon May 06 17:52:20 2019 +0200
    13.2 +++ b/test/src/SuiteMaker.cc	Mon May 13 19:30:36 2019 +0200
    13.3 @@ -33,6 +33,7 @@
    13.4  #include "EncryptMissingPrivateKeyTests.h"
    13.5  #include "CaseAndDotAddressTests.h"
    13.6  #include "UserIDAliasTests.h"
    13.7 +#include "KeyringImportTests.h"
    13.8  #include "EnterLeaveDeviceGroupTests.h"
    13.9  #include "SignOnlyTests.h"
   13.10  #include "BCCTests.h"
   13.11 @@ -46,6 +47,7 @@
   13.12  #include "HeaderKeyImportTests.h"
   13.13  #include "EncryptAttachPrivateKeyTests.h"
   13.14  #include "ExternalRevokeTests.h"
   13.15 +#include "LookupTests.h"
   13.16  #include "KeyeditTests.h"
   13.17  #include "LeastColorGroupTests.h"
   13.18  #include "DecryptAttachPrivateKeyTrustedTests.h"
   13.19 @@ -65,6 +67,7 @@
   13.20  #include "OwnKeysRetrieveTests.h"
   13.21  #include "TrustManipulationTests.h"
   13.22  #include "SyncTests.h"
   13.23 +#include "RevocationTests.h"
   13.24  #include "AppleMailTests.h"
   13.25  
   13.26  
   13.27 @@ -90,6 +93,7 @@
   13.28      "EncryptMissingPrivateKeyTests",
   13.29      "CaseAndDotAddressTests",
   13.30      "UserIDAliasTests",
   13.31 +    "KeyringImportTests",
   13.32      "EnterLeaveDeviceGroupTests",
   13.33      "SignOnlyTests",
   13.34      "BCCTests",
   13.35 @@ -103,6 +107,7 @@
   13.36      "HeaderKeyImportTests",
   13.37      "EncryptAttachPrivateKeyTests",
   13.38      "ExternalRevokeTests",
   13.39 +    "LookupTests",
   13.40      "KeyeditTests",
   13.41      "LeastColorGroupTests",
   13.42      "DecryptAttachPrivateKeyTrustedTests",
   13.43 @@ -122,11 +127,12 @@
   13.44      "OwnKeysRetrieveTests",
   13.45      "TrustManipulationTests",
   13.46      "SyncTests",
   13.47 +    "RevocationTests",
   13.48      "AppleMailTests",
   13.49  };
   13.50  
   13.51  // This file is generated, so magic constants are ok.
   13.52 -int SuiteMaker::num_suites = 54;
   13.53 +int SuiteMaker::num_suites = 57;
   13.54  
   13.55  void SuiteMaker::suitemaker_build(const char* test_class_name, const char* test_home, Test::Suite** test_suite) {
   13.56      if (strcmp(test_class_name, "MimeTests") == 0)
   13.57 @@ -171,6 +177,8 @@
   13.58          *test_suite = new CaseAndDotAddressTests(test_class_name, test_home);
   13.59      else if (strcmp(test_class_name, "UserIDAliasTests") == 0)
   13.60          *test_suite = new UserIDAliasTests(test_class_name, test_home);
   13.61 +    else if (strcmp(test_class_name, "KeyringImportTests") == 0)
   13.62 +        *test_suite = new KeyringImportTests(test_class_name, test_home);
   13.63      else if (strcmp(test_class_name, "EnterLeaveDeviceGroupTests") == 0)
   13.64          *test_suite = new EnterLeaveDeviceGroupTests(test_class_name, test_home);
   13.65      else if (strcmp(test_class_name, "SignOnlyTests") == 0)
   13.66 @@ -197,6 +205,8 @@
   13.67          *test_suite = new EncryptAttachPrivateKeyTests(test_class_name, test_home);
   13.68      else if (strcmp(test_class_name, "ExternalRevokeTests") == 0)
   13.69          *test_suite = new ExternalRevokeTests(test_class_name, test_home);
   13.70 +    else if (strcmp(test_class_name, "LookupTests") == 0)
   13.71 +        *test_suite = new LookupTests(test_class_name, test_home);
   13.72      else if (strcmp(test_class_name, "KeyeditTests") == 0)
   13.73          *test_suite = new KeyeditTests(test_class_name, test_home);
   13.74      else if (strcmp(test_class_name, "LeastColorGroupTests") == 0)
   13.75 @@ -235,6 +245,8 @@
   13.76          *test_suite = new TrustManipulationTests(test_class_name, test_home);
   13.77      else if (strcmp(test_class_name, "SyncTests") == 0)
   13.78          *test_suite = new SyncTests(test_class_name, test_home);
   13.79 +    else if (strcmp(test_class_name, "RevocationTests") == 0)
   13.80 +        *test_suite = new RevocationTests(test_class_name, test_home);
   13.81      else if (strcmp(test_class_name, "AppleMailTests") == 0)
   13.82          *test_suite = new AppleMailTests(test_class_name, test_home);
   13.83  }
    14.1 --- a/test/src/TestDriver.cc	Mon May 06 17:52:20 2019 +0200
    14.2 +++ b/test/src/TestDriver.cc	Mon May 13 19:30:36 2019 +0200
    14.3 @@ -65,8 +65,8 @@
    14.4          SuiteMaker::suitemaker_buildlist(&argv[1], argc - MIN_ARGC, common_test_home.c_str(), suites_to_run);
    14.5          
    14.6      for (std::vector<Test::Suite*>::iterator it = suites_to_run.begin(); it != suites_to_run.end(); ++it) {
    14.7 -        auto_ptr<Test::Suite> suite(*it);
    14.8 -        test_runner->add(suite); 
    14.9 +        unique_ptr<Test::Suite> suite(*it);
   14.10 +        test_runner->add(move(suite)); 
   14.11      }
   14.12  
   14.13      Test::Output* output = new Test::pEpTestOutput(); // blah
    15.1 --- a/test/src/engine_tests/DeleteKeyTests.cc	Mon May 06 17:52:20 2019 +0200
    15.2 +++ b/test/src/engine_tests/DeleteKeyTests.cc	Mon May 13 19:30:36 2019 +0200
    15.3 @@ -3,7 +3,9 @@
    15.4  
    15.5  #include <stdlib.h>
    15.6  #include <string>
    15.7 +#include <cstring>
    15.8  #include <cpptest.h>
    15.9 +#include <assert.h>
   15.10  
   15.11  #include "pEpEngine.h"
   15.12  #include "test_util.h"
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/src/engine_tests/KeyringImportTests.cc	Mon May 13 19:30:36 2019 +0200
    16.3 @@ -0,0 +1,151 @@
    16.4 +// This file is under GNU General Public License 3.0
    16.5 +// see LICENSE.txt
    16.6 +
    16.7 +#include <stdlib.h>
    16.8 +#include <string>
    16.9 +#include <iostream>
   16.10 +#include <fstream>
   16.11 +#include <cstring> // for strcmp()
   16.12 +#include "TestConstants.h"
   16.13 +
   16.14 +#include "pEpEngine.h"
   16.15 +#include "message_api.h"
   16.16 +#include "keymanagement.h"
   16.17 +#include "test_util.h"
   16.18 +
   16.19 +#include <cpptest.h>
   16.20 +#include "EngineTestSessionSuite.h"
   16.21 +#include "KeyringImportTests.h"
   16.22 +
   16.23 +using namespace std;
   16.24 +
   16.25 +KeyringImportTests::KeyringImportTests(string suitename, string test_home_dir) :
   16.26 +    EngineTestSessionSuite::EngineTestSessionSuite(suitename, test_home_dir) {
   16.27 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyringImportTests::import1"),
   16.28 +                                                                      static_cast<Func>(&KeyringImportTests::import1)));
   16.29 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("KeyringImportTests::import2"),
   16.30 +                                                                      static_cast<Func>(&KeyringImportTests::import2)));
   16.31 +}
   16.32 +
   16.33 +void KeyringImportTests::setup() {
   16.34 +    EngineTestSessionSuite::setup();
   16.35 +}
   16.36 +
   16.37 +void KeyringImportTests::tear_down() {
   16.38 +    EngineTestSessionSuite::tear_down();
   16.39 +}
   16.40 +
   16.41 +void KeyringImportTests::import1() {
   16.42 +    const string pub_key = slurp("test_keys/pub/pep-test-keyring.asc");
   16.43 +
   16.44 +    PEP_STATUS statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   16.45 +    TEST_ASSERT_MSG((statuspub == PEP_TEST_KEY_IMPORT_SUCCESS), "statuspub == PEP_STATUS_OK");
   16.46 +
   16.47 +    struct entry {
   16.48 +        const char *fingerprint;
   16.49 +        const char *address;
   16.50 +    };
   16.51 +
   16.52 +    struct entry entries[] = {
   16.53 +      { "4ABE3AAF59AC32CFE4F86500A9411D176FF00E97",
   16.54 +        "pep.test.alice@pep-project.org" },
   16.55 +      { "3D8D9423D03DDF61B60161150313D94A1CCBC7D7",
   16.56 +        "pep.test.apple@pep-project.org" },
   16.57 +      { "BFCDB7F301DEEEBBF947F29659BFF488C9C2EE39",
   16.58 +        "pep.test.bob@pep-project.org" },
   16.59 +      { "8DD4F5827B45839E9ACCA94687BDDFFB42A85A42",
   16.60 +        "pep-test-carol@pep-project.org" },
   16.61 +      { "E8AC9779A2D13A15D8D55C84B049F489BB5BCCF6",
   16.62 +        "pep-test-dave@pep-project.org" },
   16.63 +      { "1B0E197E8AE66277B8A024B9AEA69F509F8D7CBA",
   16.64 +        "pep-test-erin@pep-project.org" },
   16.65 +      { "B022B74476D8A8E1F01E55FBAB6972569A7FC670",
   16.66 +        "pep-test-frank@pep-project.org" },
   16.67 +      { "906C9B8349954E82C5623C3C8C541BD4E203586C",
   16.68 +        "pep-test-gabrielle@pep-project.org" },
   16.69 +      { "AA2E4BEB93E5FE33DEFD8BE1135CD6D170DCF575",
   16.70 +        "pep.test.john@pep-project.org" },
   16.71 +    };
   16.72 +
   16.73 +    for (int i = 0; i < sizeof(entries) / sizeof(entries[0]); i ++) {
   16.74 +        const char *address = entries[i].address;
   16.75 +        const char *fpr = entries[i].fingerprint;
   16.76 +
   16.77 +        cout << "Looking up: " << address << ", should have fingerprint: " << fpr << endl;
   16.78 +        pEp_identity *id = new_identity(address, NULL, NULL, NULL);
   16.79 +        PEP_STATUS status = update_identity(session, id);
   16.80 +        TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   16.81 +        cout << "Got: " << (id->fpr ?: "NULL") << " -> " << (id->address ?: "NULL") << endl;
   16.82 +
   16.83 +        // We should always get the same fingerprint.
   16.84 +        TEST_ASSERT_MSG((id->fpr), "id->fpr");
   16.85 +        TEST_ASSERT_MSG((strcmp(id->fpr, fpr) == 0), "strcmp(id->fpr, fpr) == 0");
   16.86 +
   16.87 +        free_identity(id);
   16.88 +    }
   16.89 +}
   16.90 +
   16.91 +void KeyringImportTests::import2() {
   16.92 +    const string pub_key = slurp("test_keys/pub/pep-test-android-keyring.pgp");
   16.93 +
   16.94 +    PEP_STATUS statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   16.95 +    TEST_ASSERT_MSG((statuspub == PEP_TEST_KEY_IMPORT_SUCCESS), "statuspub == PEP_STATUS_OK");
   16.96 +
   16.97 +    struct entry {
   16.98 +        const char *fingerprint;
   16.99 +        const char *address;
  16.100 +    };
  16.101 +
  16.102 +    // Several addresses appear multiple times in the keyring.  To
  16.103 +    // avoid teaching this function how key election works, we just
  16.104 +    // don't test those.
  16.105 +    struct entry entries[] = {
  16.106 +      // { "1D600EA0BD575C846E0A8C1008BE097B1F15FB26",
  16.107 +      //   "android01@peptest.ch" },
  16.108 +      // { "51FBBE53E9643A69D6D1F60E74E8073E2DD1F4AC",
  16.109 +      //   "test010@peptest.ch" },
  16.110 +      { "DB92DA58C7F6D6A48F7EF9DC4EBB4CED0E93C7B3",
  16.111 +        "thomas@o365.peptest.ch" },
  16.112 +      { "667A749BEC0C6F844D499D57851E58B37BD4B02E",
  16.113 +        "iostest009@peptest.ch" },
  16.114 +      { "7FCCC380455A9C2F1B080E18CEFBF78746423688",
  16.115 +        "iostest006@peptest.ch" },
  16.116 +      // { "447C595819EDB241",
  16.117 +      //   "android02@peptest.ch" },
  16.118 +      // { "474D7DE519248C2A2EFD45A2148BBDB8A9C68A1C",
  16.119 +      //   "test010@peptest.ch" },
  16.120 +      { "DBA0A1A1001396838E3A3269DF2ED8AA4A3144AA",
  16.121 +        "sva@pep-security.net" },
  16.122 +      { "DBA0A1A1001396838E3A3269DF2ED8AA4A3144AA",
  16.123 +        "bernadette@pep-security.net" },
  16.124 +      { "DBA0A1A1001396838E3A3269DF2ED8AA4A3144AA",
  16.125 +        "bernadette.laengle@pep.foundation" },
  16.126 +      { "DBA0A1A1001396838E3A3269DF2ED8AA4A3144AA",
  16.127 +        "sva@pep.foundation" },
  16.128 +      { "1E02952E9E2048ABD510261AF43CDF9D0F14C2DB",
  16.129 +        "pepegrillodev@gmail.com" },
  16.130 +      // { "E3549B2DCD26832F4F30D8D051716A5DF1F4C2BF",
  16.131 +      //   "android01@peptest.ch" },
  16.132 +      { "5CC67646D67A33D8A2E4FF849E61B9BC790E6B02",
  16.133 +        "huss@pep-project.org" },
  16.134 +      // { "911BD458F82249F0",
  16.135 +      //   "android02@peptest.ch" },
  16.136 +    };
  16.137 +
  16.138 +    for (int i = 0; i < sizeof(entries) / sizeof(entries[0]); i ++) {
  16.139 +        const char *address = entries[i].address;
  16.140 +        const char *fpr = entries[i].fingerprint;
  16.141 +
  16.142 +        cout << "Looking up: " << address << ", should have fingerprint: " << fpr << endl;
  16.143 +        pEp_identity *id = new_identity(address, NULL, NULL, NULL);
  16.144 +        PEP_STATUS status = update_identity(session, id);
  16.145 +        TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  16.146 +        cout << "Got: " << (id->fpr ?: "NULL") << " (expected: " << fpr << ") -> " << (id->address ?: "NULL") << endl;
  16.147 +
  16.148 +        // We should always get the same fingerprint.
  16.149 +        TEST_ASSERT_MSG((id->fpr), "id->fpr");
  16.150 +        TEST_ASSERT_MSG((strcmp(id->fpr, fpr) == 0), "strcmp(id->fpr, fpr) == 0");
  16.151 +
  16.152 +        free_identity(id);
  16.153 +    }
  16.154 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/src/engine_tests/LookupTests.cc	Mon May 13 19:30:36 2019 +0200
    17.3 @@ -0,0 +1,97 @@
    17.4 +// This file is under GNU General Public License 3.0
    17.5 +// see LICENSE.txt
    17.6 +
    17.7 +#include <stdlib.h>
    17.8 +#include <string>
    17.9 +#include <iostream>
   17.10 +#include <fstream>
   17.11 +#include <cstring> // for strcmp()
   17.12 +#include "TestConstants.h"
   17.13 +
   17.14 +#include "pEpEngine.h"
   17.15 +#include "message_api.h"
   17.16 +#include "keymanagement.h"
   17.17 +#include "test_util.h"
   17.18 +
   17.19 +#include <cpptest.h>
   17.20 +#include "EngineTestSessionSuite.h"
   17.21 +#include "LookupTests.h"
   17.22 +
   17.23 +using namespace std;
   17.24 +
   17.25 +LookupTests::LookupTests(string suitename, string test_home_dir) :
   17.26 +    EngineTestSessionSuite::EngineTestSessionSuite(suitename, test_home_dir) {
   17.27 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("LookupTests::lookup"),
   17.28 +                                                                      static_cast<Func>(&LookupTests::lookup)));
   17.29 +}
   17.30 +
   17.31 +void LookupTests::setup() {
   17.32 +    EngineTestSessionSuite::setup();
   17.33 +}
   17.34 +
   17.35 +void LookupTests::tear_down() {
   17.36 +    EngineTestSessionSuite::tear_down();
   17.37 +}
   17.38 +
   17.39 +void LookupTests::lookup() {
   17.40 +    // 1. create original identity
   17.41 +    const char* expected_address = "hans@xn--bcher-kva.tld";
   17.42 +    const char* fpr = "00B5BB6769B1F451705445E208AD6E9400D38894";
   17.43 +    const char* userid = "Hans";
   17.44 +    const char* username = "SuperDuperHans";
   17.45 +    const string pub_key = slurp("test_keys/pub/hans@xn--bcher-kva.tld_-0x08AD6E9400D38894_pub.asc");
   17.46 +
   17.47 +    PEP_STATUS statuspub = import_key(session, pub_key.c_str(), pub_key.length(), NULL);
   17.48 +    TEST_ASSERT_MSG((statuspub == PEP_TEST_KEY_IMPORT_SUCCESS), "statuspub == PEP_STATUS_OK");
   17.49 +
   17.50 +    pEp_identity* hans = new_identity(expected_address, NULL, userid, username);
   17.51 +
   17.52 +    PEP_STATUS status = set_identity(session, hans);
   17.53 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   17.54 +    free_identity(hans);
   17.55 +
   17.56 +    // Lookup using different spellings of the email address.
   17.57 +    const char *addresses[] = {
   17.58 +        // Check case folding.
   17.59 +        "hans@xn--bcher-kva.tld",
   17.60 +        "Hans@xn--bcher-kva.tld",
   17.61 +        "Hans@xn--Bcher-kva.tld",
   17.62 +
   17.63 +        // Check puny code normalization.  Note: only Sequoia does
   17.64 +        // puny code normalization.
   17.65 +#ifdef USE_SEQUOIA
   17.66 +        "hans@bücher.tld",
   17.67 +        "Hans@bücher.tld",
   17.68 +        "HANS@BÜCHER.TLD",
   17.69 +#endif
   17.70 +    };
   17.71 +
   17.72 +    for (int i = 0; i < sizeof(addresses) / sizeof(addresses[0]); i ++) {
   17.73 +        const char *address = addresses[i];
   17.74 +
   17.75 +        pEp_identity *hans = new_identity(address, NULL, NULL, NULL); 
   17.76 +        PEP_STATUS status = update_identity(session, hans);
   17.77 +        TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   17.78 +
   17.79 +        // We should always get the same fingerprint.
   17.80 +        TEST_ASSERT_MSG((hans->fpr), "hans->fpr");
   17.81 +        TEST_ASSERT_MSG((strcmp(hans->fpr, fpr) == 0), "strcmp(hans->fpr, fpr) == 0");
   17.82 +
   17.83 +        // We don't compare hans->username or hans->user_id in case
   17.84 +        // the engine doesn't have the same concept of equality (as of
   17.85 +        // 2019.5, this is the case: pgp_sequoia.c does puny code
   17.86 +        // normalization, but the engine doesn't).
   17.87 +        TEST_ASSERT_MSG((hans->username), "hans->username");
   17.88 +        TEST_ASSERT_MSG((hans->user_id), "hans->user_id");
   17.89 +
   17.90 +        // We should get the address that we looked up; no
   17.91 +        // normalization is done.
   17.92 +        TEST_ASSERT_MSG((strcmp(hans->address, address) == 0), "strcmp(hans->address, address) == 0");
   17.93 +
   17.94 +        TEST_ASSERT_MSG((!hans->me), "!hans->me"); 
   17.95 +        TEST_ASSERT_MSG((hans->comm_type == PEP_ct_OpenPGP_unconfirmed), "hans->comm_type == PEP_ct_OpenPGP_unconfirmed");
   17.96 +
   17.97 +        cout << "PASS: update_identity() correctly retrieved OpenPGP key for '" << expected_address << "' using '" << address << "'" << endl << endl;
   17.98 +        free_identity(hans);
   17.99 +    }
  17.100 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/test/src/engine_tests/RevocationTests.cc	Mon May 13 19:30:36 2019 +0200
    18.3 @@ -0,0 +1,59 @@
    18.4 +// This file is under GNU General Public License 3.0
    18.5 +// see LICENSE.txt
    18.6 +
    18.7 +#include <stdlib.h>
    18.8 +#include <string>
    18.9 +#include <iostream>
   18.10 +#include <fstream>
   18.11 +#include <cstring> // for strcmp()
   18.12 +#include "TestConstants.h"
   18.13 +
   18.14 +#include "pEpEngine.h"
   18.15 +#include "message_api.h"
   18.16 +#include "keymanagement.h"
   18.17 +#include "test_util.h"
   18.18 +
   18.19 +#include <cpptest.h>
   18.20 +#include "EngineTestSessionSuite.h"
   18.21 +#include "RevocationTests.h"
   18.22 +
   18.23 +using namespace std;
   18.24 +
   18.25 +RevocationTests::RevocationTests(string suitename, string test_home_dir) :
   18.26 +    EngineTestSessionSuite::EngineTestSessionSuite(suitename, test_home_dir) {
   18.27 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("RevocationTests::revocation"),
   18.28 +                                                                      static_cast<Func>(&RevocationTests::revocation)));
   18.29 +}
   18.30 +
   18.31 +void RevocationTests::setup() {
   18.32 +    EngineTestSessionSuite::setup();
   18.33 +}
   18.34 +
   18.35 +void RevocationTests::tear_down() {
   18.36 +    EngineTestSessionSuite::tear_down();
   18.37 +}
   18.38 +
   18.39 +void RevocationTests::revocation() {
   18.40 +    // Read the key.
   18.41 +    const string key = slurp("test_keys/priv/pep-test-linda-0xDCD555B6055ADE22_priv.asc");
   18.42 +
   18.43 +    PEP_STATUS status = import_key(session, key.c_str(), key.length(), NULL);
   18.44 +    TEST_ASSERT_MSG((status == PEP_TEST_KEY_IMPORT_SUCCESS), "status == PEP_STATUS_OK");
   18.45 +
   18.46 +    pEp_identity* pre = new_identity("linda@example.org", NULL, NULL, NULL);
   18.47 +    status = update_identity(session, pre);
   18.48 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   18.49 +    TEST_ASSERT_MSG((pre->comm_type == PEP_ct_OpenPGP_unconfirmed), tl_ct_string(pre->comm_type));
   18.50 +
   18.51 +    // Read in the revocation certificate.
   18.52 +    const string rev = slurp("test_keys/priv/pep-test-linda-0xDCD555B6055ADE22.rev");
   18.53 +
   18.54 +    status = import_key(session, rev.c_str(), rev.length(), NULL);
   18.55 +    TEST_ASSERT_MSG((status == PEP_TEST_KEY_IMPORT_SUCCESS), "status == PEP_STATUS_OK");
   18.56 +
   18.57 +    pEp_identity* post = new_identity("linda@example.org", NULL, NULL, NULL);
   18.58 +    status = update_identity(session, post);
   18.59 +    // PEP_KEY_UNSUITABLE => revoked (or something similar).
   18.60 +    TEST_ASSERT_MSG((status == PEP_KEY_UNSUITABLE), tl_status_string(status));
   18.61 +    TEST_ASSERT_MSG((post->comm_type == PEP_ct_key_revoked), tl_ct_string(post->comm_type));
   18.62 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/test/test_keys/priv/hans@xn--bcher-kva.tld_-0x08AD6E9400D38894_priv.asc	Mon May 13 19:30:36 2019 +0200
    19.3 @@ -0,0 +1,138 @@
    19.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    19.5 +
    19.6 +xcSYBFzR6V0BDACkJ2yRZAaR7tg6jAC87LLICjd39xnD/Ra9D3Elld5QTHZ2GXw+
    19.7 +8v1er/ZYcvS3JPZsjDvIeg5bRV24IpghWyfRvjBivLlAV9PCWSpfCqj0xnzM7HaU
    19.8 +UQbPg/Bwtf7m8A3YC16pBIbmGUHfIL6LUY7Fd4dLKu1UELuhKn/Tn6X9YuO4Isah
    19.9 +w2U4lbobzFvH7PKkBuG3+sYL7JhE/ArDTIWaSoszvPtxTg/hfSj1rZmfYrClzcB8
   19.10 +aqoilhmRdYX1DNk4c7bsg513XirqTm0lJMK23hOJithBsGoC6n6Tm3X9NC/a4hmE
   19.11 +Fly8U8Y3wW26WUUR0gPfp16c5GFhLlOuRwOdO0D+WnEOnw+Aq1IRd+LtLq4psNRv
   19.12 +D7dxI299tBuybn26fQAUXmMqF+MSOqyqKegi6IIiD1jFDAg3t0rSu77pphMm3ANS
   19.13 +uuTJ6xrhnS5YwRQ5/czJu6MFK33ycWw/6PLnaEgrNS7XjHXsgSPgjoEPB5+hAwDn
   19.14 +roW0DnRdmk2HhnsAEQEAAQAMAJdUZOkP3mKwXpRytsd0Kkjx6jrlCNK+QjUexD9T
   19.15 +DzTVmKu9SOY7WkrtStw1ddZU8/wTt5VUuGF57DExay/s+iOJAtAzjVB85xIW41Hk
   19.16 +4OdvCGReZd7LZ8zspD8z+H7rtMeDi8ujCb2ccTaC2EZVdJokXAx20X2bQ24LYPY2
   19.17 +Cm8yuB3rqVQ9btYgagbweXgwv2tpkLLsM6GQhrup4z4yEESyDewvf1nwDgHhQV5j
   19.18 +oOjnsVPY/2dzac8iswV+43SKV0hrh93JPKP1OPoIx8WvbAz1nkmUkaxKfJNrSOZT
   19.19 +57XNNJM6FXGJqJVUVnwe43sltWRoCJaAVQqbVf8bL9b+/FVInXGqYkrnbCvuzeIP
   19.20 +Dq8foWsZueu3jFO4OuxlizxWDuh4MHpcWKU2AYjs8H8kLlROcgFOXYme0GCx0GoH
   19.21 +fBcnA0U3emC5SUc9glnZT1UXuOVy0PBHZLQtosSl1VaS3zIXpWl7K5WEAt29EKHb
   19.22 +hSfrTXub2kIWZwC6lx//8PS/GQYAxxgOqSyvNTB8ZUxTsHmzkMGeL3QHiz5sObwk
   19.23 +xrYXkpUKIzgGUK8fAKNtVURgrNWCcj09WeILaUPeChpsnu+3TZZa8NNnzDMTgb/M
   19.24 +aBv8uR/SZxJBgbgNmyJjVPqjJLXi4CyYn4xIm7kiAusyVdWpeGxVnMAd7DNzNaoS
   19.25 +ESYYAlxZZ3QBSi8uGzTj7X4xi4luIlJgY8Fvp6V/FyEWvpDNfCqKszCn4JgB12pI
   19.26 +x++Hzwlxp7TNxXOhYYYBvKsqEfiVBgDTEsR28bf8xf0hr0Im+UeCvyMJ84OSCuvt
   19.27 +J9dQCef7tn0TB1iWO1Jl619YM3gaCgKN1GOMHlV9cjtJ4vIsYjY2fxhoIN9uwuKY
   19.28 +rRD5MDxct5Cx35Kg7kIZaEsGJqt5Bnm3K5DjxvoN50UYloRq+nbxT6THPTFUkBVR
   19.29 +OjzJVKThLoVWKLoQOZrTI9mk8Qv8cfc2mSni5t7bF4klRIVMoeeGqS9zDsOYqnHP
   19.30 +8leYLXRK7V1WfSt8XIFevf1oYkoR7s8F+wQnORG8JZWKYN1L4oRROg7RYUYaZMsh
   19.31 +tR0GTrQOap9Dv3nDqL306KZr12lf6IRF0CWhZtvqWe56wPQB5qvgU2hIwUk/3kG+
   19.32 +396HwoeyuzpuA/Za1CQ4Q1sHmNUiault1Jpmz5WwDQocby+EFwVaps48MaEMGCPS
   19.33 +Tjc5vV7kNdevYPNDh2ytDs61KVAxSJxzE8XIQmhTbJl1ifhbLkUzIgbBpKXPvA2C
   19.34 +aa4C97xEEb8rtbZ44usNbgXlS5pMMnThzc3hwsECBB8BCgA2Ah4DApsBBYJc0eld
   19.35 +BYkFn6YAFiEEALW7Z2mx9FFwVEXiCK1ulADTiJQJEAitbpQA04iUAhUKAACY6gwA
   19.36 +kN2XvosfWgZtQsAuHR5+amQvqvGj+yd45LVRRaNs3b/45vNfifjp84DWLl/TJiZh
   19.37 +LVxAWfaIO662ZeWFPgRQLFM0B3PXFGY8pF6Cfqt6NeXYa/yOU5KAwwcqpzPd0nA/
   19.38 +A4QH1glNC0tRQHKL/UVMYU7QILRC0GbbJNX9TqtG5zHFe3+JPxbBc465wxcJPZEO
   19.39 +6Fd5QM/nFJZrMCsWf2UpBg2dkf6M6Jv9pMSG/rVCDtYhNZt+GZu+/1sRi8ryZVAl
   19.40 +20GlOpji7B1PVyezusDs+NcDZ6u1cTpiNirXrpoH9AomukPVcPYyhV8Co5smX7pQ
   19.41 +IDR3LmwKXcE/JGN7ocH4C2FwwdcgNtJ4kz9EJ+d3v2iplocNa9Ev/0J2gtixzJ64
   19.42 +0J03zZ9XR1wgdr0Y06JDXqX7rJz8Vj9p853/2qdsCcBPylpm0RC+ymgHBHMOuRYx
   19.43 +nkFYN+1CzULKxLBHfhBuL2hRONieaeS6dYbNpM8haBgJlSINX0myWPh5fPqHRviU
   19.44 +zR1IYW5zIDxoYW5zQHhuLS1iY2hlci1rdmEudGxkPsLBAgQTAQoANgIeAwKbAQWJ
   19.45 +BZ+mAAIVCgWCXNHpXRYhBAC1u2dpsfRRcFRF4gitbpQA04iUCRAIrW6UANOIlAAA
   19.46 +FGQL/15QxKSU22xKtJfm0qPpehjRQVmykzsj6hbPYxpmFmRAN6UJi4u2w5/6VDxc
   19.47 +IuzSuIlV4JSuXiNYPPDKCvUnTEd9HE4PUjpswqXx86mcr2LNCoIcDl7FEFbMZxgg
   19.48 +5em9rZ9SgJAf6N0X421P32mNo6rAF1t8VEQcWUsuq1mq6DHBGj36Dr7y0S6wsgrb
   19.49 +mfoAPMnbCGo9zvwAaLR06yjUaRpIAu+GS4WvCrgoj4IFm2uufOypmGjRO0iL1pg0
   19.50 +MELqrWc0XgcNrbUoMLrb1KSqrKyV94jROv1Wv0lIyh5CJfnHMe2xGCvnDQS/DTAG
   19.51 +Fkcu60Qk+QqKb9WCauPAD8xqekCcWTZry0u/Wna2KoKAbqpDhTWNDzuL3dyTVce4
   19.52 +R/w+ZKnQUfVe/3ThSn7VID66HiiygNfrTPJBemjw5j8NvRGkgTJpprG8+zmZSbgr
   19.53 +krvRWLmo+YhNng+lhXZ1UH3y+8lkHrDOc0MsW71+r7naO552w/DkcJ0TQ6rHNOvh
   19.54 +jQ368MfEmARc0eleAQwA491l+GgZIIz8882KRUjhMWBguTA8EobBBpgiP/xiIE82
   19.55 +UGWlq8ORDdrmxiuoJ1nEf5pJ0JXCi3uujz8q6hZo6JS4ci447DIDaXVWSFQ3Goz5
   19.56 +7G6Gi7JfMMaH6dtShYru/np/+wNM2vxuxMhBrd5DWA0uTk33R8C/Jp2PhM9MVpiK
   19.57 +F+mt1/tJc9JCOAi+J2r9bk8nzT6gepPI+5u0eyp40ZzY6ydd5vGDD+X2dz07MLzz
   19.58 +VxKR8StdAmcoOGz8FZNMnkuy+J/M+KgvpnTNghH+4markQRCTkel+J8hBtdMDFxa
   19.59 +90wlr0PF+HaHKpCGHNTr1SSRTbxSWG2QG/Ym4srN07yHgJN5QiZc3dBG3OuIQx/S
   19.60 +zQz5d+lQs9KWKZpMj6C2mTksW5bYNGBFGqM6h9Wh3FI+Hw+naS+CN2aVhjJTHWGb
   19.61 +3DOMhkNpG7lkZeInjO6zo77ifqe+WvD9jkeGlM/QNEydo0BF1qonxEFDKgdAtL+1
   19.62 +cNs5K8B/7HeTGIN3Zq6pABEBAAEADACUDKSVSmWRDanIanJ9Y8XVBA60JA/T5bQC
   19.63 +qdQPCNdksLLUd8a1nCJiAylP9suRjbSrR77QBI3bfKfFMMCcSaUuAHr6zOd1J2Wq
   19.64 +Hm/KHNWUraYwpPtMRr+sfEGQg0zRsZxowYTnvZQw8DS0LHzoD/JngmDkxal1+Fj6
   19.65 +KQM3wkySMxf+Q3kNTJrD4wfdSmjqSYySIGH268ru+ZhrShZws/6+Co+x8ekEBUUn
   19.66 +jj2d6a3Mk+fzWgBy1r7esdGjH8SF7CZwlbv9d6U6k2CjOCzqR2MrlxgUsPZG/re7
   19.67 +qh+KWi1iea+nj4mhWtMjezEGKR7nxhP+PDQApkjQ9QjTo3zEO1p3XYuL999SWeon
   19.68 +g1+ClB2RSY31YYFJ6m1V1OIbHt9hYno74P72kqhwCEkrrBBON/9Hh6LHgZ/mGd9l
   19.69 +D4P2ePJkmz5jJI6aZgoRaHHy/kjpxHIB+nUQKAYg5F1eK1Y5AoRANcPiYpo/VAcB
   19.70 +v+aQ8D402z31Bwo6ag0v0nJgJzfLQwEGAORMYsPQ6VuUT+YEXVATUyfg6T642dAr
   19.71 +Ch83reqlnx7KWNeS16AuqaY8yMkWlB0X1ToQ834+9kF6AA8BeCU3jQN3bgY/CYVL
   19.72 +MgExuLxPHBBrzIFXHdQupd4IITXxeeCe/xWGjG7x+lbhrr2qGmTFLjy0Z/fDs0KZ
   19.73 +ZgxevYCFyTa4V94SAld9lpGlUHw+4WALqHmnUk0N7WWua3DLYvE+rtzKmH8qKxEi
   19.74 +Fhwg6J0pWAgqf4WVhB9r/Ahm9ZtBfmnd4QYA/4OLnD9/PaBYRB9rNWPKiNrtlGEF
   19.75 +kfzZQRVIDH+LoRWX/cjYUCqZzy85u/y5ugRI3u18iNolsOQyd/sVP37O1RdurxCw
   19.76 +0rPbgwxgpwHSRMG5gQK34JKyk72s8TNePwz/b0kPSFYdTnNwk9sekndTxLSdSlzY
   19.77 +Xt9snCkK158/Lf8hSehRg2BzOKdjsLCmy4Z3D33pmgGF02EJ0wb2KuTps6YXiXiS
   19.78 +jnioc+4dbS8yfWEfh0kaPZjtz/NiIOWOLJnJBf93vqn9L7zi3ugDAWL3tGsLyzyM
   19.79 +SCkKpXqvMVNx1DzqQLIOAXGA7oF9am3ZxMg/0s+wKQtKBJlyd5fr6hb3QulkooQS
   19.80 +3khDMDzGYdrwpQAN0ZH8upDGpvKuaXgJdqVdhrKJxtV3AFzaEKcO/oTeWsXSN6Fg
   19.81 +vP6K3ify9gdvLpylFamtm+m+qKqwWQCdW1Cc/UNBppuvvcd/u07HHQ8w7dKeMFm0
   19.82 +hIkJO4mMWwd3AxjCJsj5rC2czbK1FwVN3858Oqbb48LCuAQYAQoANgIeAwKbAgWJ
   19.83 +BZ+mAAIVCgWCXNHpXhYhBAC1u2dpsfRRcFRF4gitbpQA04iUCRAIrW6UANOIlAG2
   19.84 +wPSgBBkBCgAnBYJc0eleFiEEZ433xCA2cbfsXHpnQBe0N01yqsMJEEAXtDdNcqrD
   19.85 +AADRkQv/RBZvOZmo0wbGE6WTYRvUZJNdiTEYxo8YOxlEfw2GWCl0/QQ+Eh8XFh6J
   19.86 +nc4V70UiwwHuZ0YFFXxA1c6K8zhcBkq+n5EMMPTTCF/lmqF3qqbLGG7dwy0yVfry
   19.87 +ze79mvz24mAhD7vaZ3m9IdNvLIKd+LIWaD08GbpbTc+UNCb7iPYx/LN23lNs/grT
   19.88 +LHK1KTWMq4T11SSrdeT8j3d5Ax3UhvyRuWL+RKfd8WKpfl39ZbPl7lQYs2uyoKT3
   19.89 +RyMI66EKXKGTY2UNjbMo2OyBY3UIvdjNVt80kPv7MVzBOQlUkB7IEUuL9UHLFKug
   19.90 +IL2gBsWdJm/tnxm/OVzOjS9j6P1UqwUdNNh9nXlpIvQaifxy0my0SIs6vfnRVLOL
   19.91 +XUPQ+Mmi4midVq1plUUyPxrJd3mw8cEvHZY2xVRqInSCAtFHkA50mAykf/bOh9zP
   19.92 +2xujEdMjSVT//dUs8W6gTHvqXRMM1axpK95CA7ULZY77pHH2ZEYxZ6jxSiHfNhDk
   19.93 +1AKfaqhvX5wL/jEJ0e5p8ebT1Bei6ohPUcI02YN6LUWOqlRHub4u2uPrrYAbLtY/
   19.94 +u6p4x7bOyri3j5iaglVGCsQ2Yrq9ejED/2bb59Hi0PtIBcBsIR/Vop/rEADSsciu
   19.95 +Tb6odP+5JGnLPda/Xt24Cd1ZXXa9GI/4ZEQtqiMZZsf82Z4r3yYsfpViTPlps/Xa
   19.96 +9kKK0NMfrrXvqfmPsOzy+z+PpBIqViHkV4IzOS88xOBk3Ad6RWbzPfQabkI7UfJa
   19.97 +/aki/jKLxrQluQg+cBE4gclnBy+x3EoxmIjg0TucZO5jHkTRwUmFncyg+fQ71sDj
   19.98 +ilPzPdN9K5NKNepVJSy4v3N4gAcgvOPIXyucvbVvy45lQQgf9HIBgSu5oFKX2gnw
   19.99 +Gw9nxBwZ2XcQAX9XYn56AVVARqX5YvOgMXlclnUMm9JCTzBHyIt0oPlzWWwYCwLX
  19.100 ++8ToLbkq4mR1pMifp0ELrvnITG5lAx2IvB3D/UzZegR09e6MF28XqBEZnzfcn/ii
  19.101 +XCQjo5UhelrKIcfEmARc0eleAQwA8HDSEz2+Awzm3d0W5RKZeMOGMp+ts1DGZomp
  19.102 +SUS8ot1H2wD+StEJc4ryxZyWRaGzXRiJbld5WqcxK22iMPPPgmiW+5j2NamqDUZm
  19.103 +3G4QOFzDNc10urqB3jP2FqUca36OWHa6t9IQAy5HBz21S9urnUTcNJBha7xC5Blt
  19.104 +6Um8o8ah2eqf/CblNP75cqq4nxwlEsj+Rh64KsI9cLVfaCh7XJUMD6aphc32RqN4
  19.105 +a9j89+HXXF+Qc1XgFmAFI80iS4Kv/b6fI0FiTfUsE8KwtrgFU36Cw/jM4J/03FdO
  19.106 +KZo5/036I9WNg5KnDEKYYCsdbpB4ZxpHLmtBAv92DnrXZ+EYZJZ8ijfnsx2zZkgl
  19.107 +AzMSjzHZd3v4tuAlb9du1Q7YKsj0/YzWLJGraeRBJG1Zg4ZNLTg20ZfJJzWEjUhq
  19.108 +AlwxfKmB+thRL+BYOAlHDGy1YPAof9sQ3azIRR8gkF+qflawRnw2aCvs1E+EGt52
  19.109 +BEV7CPd26ZPXY90lp38k3eQkz2e9ABEBAAEAC/0TdJ2bDvjsGEQqGbS7jni6q9+V
  19.110 +AxS0GMolC+iV1CkLaKpizz7EYQvJvKmOUfBa7A2ub8jXE97u9e5lnDZujZvx6nKl
  19.111 +IyhxCSyIbHTwSzumw+LL3LcgUO0nRL8Z7/xPumrcP6c2Lpo7F6iJrnWYEMtfK25C
  19.112 +Fpi7df1XpbMeGGhaPD1me7S8W41ab3NR0vyja0yYq4jftaajVxpPn2176SKqSCk0
  19.113 +rwCyogrWhm29FE7L5AtgHx96Ja2/Qb/IuNWYlJdu4TuHms5u9I2w27n2c8a8yFLh
  19.114 +lhNLzAd1GoKmD7VtA45rG1aT8baWWEJAFNsXRENbthCcLd2Azbkv/5xdXPKd4K+n
  19.115 +ReukZhtwUQAsNovhv0imCHSPGsZsxYa/BYyGfGl77GA9CiKaBcKCsrVtIC90Upmv
  19.116 +CgMeaGtVvtgOL6zdbG+2oqL6mvSYzNbw/9/s3z93veCNmvBhfoVtQGY2ckzV/y4y
  19.117 +2irLtgvRnbC9Qtf0GHmbkArBrDJaVOAfmxdRJsUGAPNIT8PA4/ls56RtkDDml5Gu
  19.118 +xi16akTHsa8vF4PxCDWhiZ07kVto7IupunoinD5iRF5DUYEtXlLdZwxSh3V2C6eF
  19.119 +XmG02guivt2v87X+20GNb2naH3h5/HpIks46oNu0984lQ6NKWLvh3G88VHoOWMxj
  19.120 +mCiWF6Tx9tcZrXe5mXFpw2B3WVOIaRXQTFHvKT7kVV4kWjk78gA342s0AF7iFdAL
  19.121 +j9k+mtmjTjkISrRs9t0aWImWcwdd3Q/LMZClgCJ+CwYA/QJ6x50qrpCiyrI1g3cZ
  19.122 +DnfxBLTkke7LWj9AnMLaYD4o2rUhaUV18xygq4TyuVwVCyLtpsAAMyOm8SBUV1he
  19.123 +VLsde//MhDQk7rjmLRERTAqLTJPFql+FVJCShr4IGD2/eV4zB3NFJ72HM7Vh7NxK
  19.124 +Ft8L+KBEiGrD0cl3UHovhlWnkpb1MaXW6WHhZGCicrRiErthwJv+wCcofqG4wexD
  19.125 +Kvxxvo5t76Adwt42wVwBfrsAu4kI8W0t62ZmRLzu6PZXBf9FQxf4+OyNnxkSBdOl
  19.126 +5gwfshm2ds3k9oHRRYQULD+XtmK/D4w4IgeSbI7w2Zp+N9PQ3siRvwODWn+RfP4v
  19.127 +hZs+Cki4OhDsjD7d7UoSCmKKXmfBYx2QE8BIWEyUs3KyNRSMDs19vV3tmLqJ+kyi
  19.128 +dYQv9p979UV7NyAF8PIakEiXUM7JWQNT6lmd39CltHtRG0I0J9VbNZXOKisqXDax
  19.129 +U+al6mBfcNLCkVBqlEtHG/cIJctQx7fvLV3G/MmWdDn6xHrgw8LBAgQYAQoANgIe
  19.130 +AwKbDAWJBZ+mAAILCQWCXNHpXhYhBAC1u2dpsfRRcFRF4gitbpQA04iUCRAIrW6U
  19.131 +ANOIlAAAAjsL/AwrdiMqx6pImsSYZi6+pWCwn25Lir/vdT2INly2kx3KNym32IBf
  19.132 +s6QIeCYpPhReHSJUu99gfB3UiMZelYzARcSn1b+9qR3nW02zmd5NfDI/RX9oiZsY
  19.133 +Yw62x/mAvoKdjTus4gq30EJVKB98bZBftCl8PPSm//485WDN5zqbd1/KH+9HDCHZ
  19.134 +W2Yu80SOhGUc6F2pkSRkQh0YoOFFjYJklMb057BPQx3uN7hZz/Bk2lBGQzg0YHBp
  19.135 +a+/UIKSW/Y87PvJrjK5wG2wP0rxNfZS+Ph6+dYT+E7NLxnlqPN8hsYxpg2wOQ372
  19.136 +DCQcYhcyh2bsyFFjtQQb7tYGuM0R1myBa+j5ZEiPgfbhzmgd18Z5iOhTWnk/iO+A
  19.137 +knt5dIVvqyRQrvnfmVN5xgmGAGT3NwMGBLTyehe2nATAsq1hscxNXSE/x+SbbNSt
  19.138 +MT67Qq/lEyVrXxb1Xq6kTfN09f91oDdVU/9AJxiSzE56a5vfMqJHXMK5By2UI4kO
  19.139 +X3Q7oXjkZBenzg==
  19.140 +=ox8H
  19.141 +-----END PGP PRIVATE KEY BLOCK-----
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/test_keys/priv/pep-test-linda-0xDCD555B6055ADE22.rev	Mon May 13 19:30:36 2019 +0200
    20.3 @@ -0,0 +1,14 @@
    20.4 +-----BEGIN PGP SIGNATURE-----
    20.5 +
    20.6 +wsEBBCABCgA1BYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWL
    20.7 +DR0AVW5zcGVjaWZpZWQAAMQTDADVJWlSCAdAkYixuNih9en5BHflzgfSDGgBqUKZ
    20.8 +NZ+FQyHqWLy6gkcZaXPOKz5PbMuygyPqvRvJtwpYXpGoI4gLHi/YyN4UTQT8ZzcH
    20.9 +wQeB/TZagrnHx6oKCKxnQziQGUfZczxRSAl2iL0f1geZ1kL1Czs0qH16I9jQU1MI
   20.10 +z9zgjYgKPmucuWRj/gQdS4SI0z+m4ZM5YkbhUC7njv18Qya0H5JS+7vn81Up1+9j
   20.11 +IJwVVCI0HfFRWA3FPCZBuY3CyTk40xmHvBWm8/b/YQkXJOJxsSvNe95jvHSHyaVQ
   20.12 +jlL1QYhJigp/fzQ/wDpB3ig6PFlpJa5CunWTJRj/NTCWoKKDhWtnJlDSTLIw/sdE
   20.13 +U9hMAR9rFARRRI3IFfNQdW5fsYtka2Dob+x63kMBoulfbdpf4pz15zf3MkZL9F3m
   20.14 +ZOYmcL88HXGjnmLTVeKx7fJMGBzpsXbjbULjJrJsRQbFfcqJqUN4p9cIiunuOSWJ
   20.15 +fLJXpEV60hLvznXS00fVFmsAGBo=
   20.16 +=wskl
   20.17 +-----END PGP SIGNATURE-----
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/test/test_keys/priv/pep-test-linda-0xDCD555B6055ADE22_priv.asc	Mon May 13 19:30:36 2019 +0200
    21.3 @@ -0,0 +1,139 @@
    21.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    21.5 +
    21.6 +xcSYBFzUGDUBDADfcLC79rkUBAKvkYtZ3Gg+rPXCIL/7PKB/MPa/Mt6hwCRuQLSZ
    21.7 +O0SVAcBhIwNiWNmQAQx6YKN0niCw3fPoTg+KyVqn6zlfRVUZOHOUCqGZrqAI8k0U
    21.8 +ZgJRy3tC34L9F4QsLQ0MLFBC4+Yh+Snv7Wb8zdIqTKDR/jCny2SF7jULB/noQ7sG
    21.9 +aVSyXoZyBIgvWUoBnhc/jYzfUtRHccaow6BA3ZbG91yM21ERv9IgxYIMZfdm38oM
   21.10 +/pOEhRXDce+LTZ37cDDKjqOWi2o27AEHR8I9ofV4ZifBgf9pxUjFn/GNOmLI4rk/
   21.11 +PIc6uRSpkShnQXcFsIKAqaWbquxOvTrR/wrDwz+k5lziuUZDm3hHuYDWYA671BYg
   21.12 +SBkmQNqkOPp7Vbgqzw4xLt7jQLxV8o3DDUme7rwCfuDUzcn5pgl2IuxD9BXuz+m0
   21.13 +97mD9oJs/kwBozRXupXXzx6gU1OC/M0FFzHa2TlUgQl1CSY6JvidO0r/anbOgbGE
   21.14 +0eH7zmQImSjIuBsAEQEAAQAMAJmnWSIpTKUjDOXHZNjq5RUUw/w3oU4YJxbQiR56
   21.15 +0PbStzrKbGdjhoohpjYmadFb4GFTF02g30b25uw59d0usSlzxk/rRozplNe/JlwL
   21.16 +441XtN3yImeArt+o2p7mLaH2ZgIrCOnyH0+ggUWjnt9LlqMKtxg3kfBWqQb6q6oe
   21.17 +YYOwfH7o9Ng33vK6ZiJKU4ycDnSGTt55bQK2ZxyqdT7hKHby6xjwSkjjGSDnlIzM
   21.18 +xd3Y0QWBp+S/vJpJGupIk75sJIsKruGjX09lpSMWJG0aG8XGvGrAF/RWUs4OSnrp
   21.19 +Aql0qq1tiCujzQ/YiESLqz1Bdp/fCNMmUPqLuKyMvsDehznIvNxzRLxplIXBNqhb
   21.20 +ZWh98mknYxi1DAgk+2X5Ocilvgspn0a0TSfuT6cLC/CDYnUfPZfviY35A/JIm6SK
   21.21 +i6dEWn413F+Vzvn59LG++Ue4dQwXwUqr8HrCDk2Cllk7+4bfhWZMwPzXus/d4erK
   21.22 +248NbiDxtpp+olILs1pEVlt1YQYA6DfJSK2VyscOmlpKu0rwP4eq6rDHItviIDhA
   21.23 +y6jdCGe9b/C6G4397q4IKy3aM2zhsBizYMfAf1OXuoOiHf6ZR5bLTDI6DA0bI9mx
   21.24 +wyGIKoIhXI+59PJaW2ENqqJvljW8PpjdMf6gJq9vcHf6AbvceHSnBHdCZgmKEUg4
   21.25 +Q94DZbY/FNKradCFFM9+mKrLNzXURYVDotiJ19MnAJq+G+qG1skKBwqyF3An183X
   21.26 +cdp504smbANyyVmKv79egpCpb24HBgD2UsXSQQXfjUGAMckutU/HJgaQLqXfHmfJ
   21.27 +vOEGgposfI3uxJFd01c4ssa18RB8gvgqARhjWLnpqzi4o5hOxXsva+wr5YxKIO1w
   21.28 +kQNss7Q2g/UaOtDRyi/1yfIKCOCLGyyzNL8AqvDBi+r10qCvn0CdI+KOTZd+f3Ba
   21.29 +clLQfMHeQ6VZopIsDuDphgrrjJWWi3n+L7N8QWJfSXpU+yHFPS6Z2M/FsNRqBaYG
   21.30 +DPU5B3yRxXkn5WEV6o5C9FbDc05uYE0GAOdda4hWbEoMOJLFpD9BLOYGPdEwDoFk
   21.31 +cbn9HuCf5yhWATJevHKcZ8p0QtqyGcO1MxhnGKRE+MEBg/3K5PYuNHiFVWYt7UZ+
   21.32 +Ppd9GHCztEEhhMT1Loc9wLoUyn/DD6OGw5HJr/jQwEeQVi+hMAC/8XCvPWkB3jgd
   21.33 +kV6Pp7O9/xQwNL+mMoKnWDm872riUA7GNztdKnYNlzEls4nCyfrFHWPrsygpLnY7
   21.34 +c3hGaGIaW1TvxhszjhMGimY+bfR4aNYJ7eMcwsECBB8BCgA2Ah4DApsBBYJc1Bg1
   21.35 +BYkFn6YAFiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAhUKAABmgQwA
   21.36 +2ueTnP2ki/cEPcyxmTpl7PAVSaxRqxEpEa4lofjklFbOhaGrOsfbkQvINAYhMoXP
   21.37 +xDTNj0VrRf+Ffv1FACznkG2Tmm6U255HfmJjdlHICo7yKOcoMUvifgURcx1p5nbF
   21.38 +F9r/AUWRg9Cz9VXrnUJnnCZqd1AZpz1K3NlWrSlAJJmtAgXIqX4YoWoJwhj+pKIT
   21.39 +hDSF9ozKWobN9A7HCkLwk5JFh690SSCe/X/Nl1rUXd+jXlor3OKdojvc4BPOBURE
   21.40 +PSJ/GqaGrkELLGQ01LF17ThB9XCfSPh3D/wG/UQR2T+FckiSdpy4jidWN8TgqigD
   21.41 +6zFzSveXswWiFk8+OKmtVN2NTcOCsO1l/UCgiL8pYG7OShJvhBndd9pCT+R6mDNj
   21.42 +IOTSdwMPNag02zFAFRCv2hXn+lgJczIy51r7ev7ONm7fF9AHZLqDqH/zWyfFQjdo
   21.43 +z5TKloHl3fZze1sphv3isUYZkA9gOeYjAj1g0A9dAvxPGLC40E1a/20xiNZxP6UQ
   21.44 +zUlMaW5kYSBNYXJ5IFBhdHJpY2lhIERlYm9yYWggQmFyYmFyYSBTdXNhbiBNYXJp
   21.45 +YSBOYW5jeSA8bGluZGFAZXhhbXBsZS5vcmc+wsECBBMBCgA2Ah4DApsBBYkFn6YA
   21.46 +AhUKBYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAADAFgv+
   21.47 +Omxaoo3pQVZJ4nrBOBiWJvEQ8fUTjl3VSTzE47DihWcCJQurlI5yB6yvtmuYvQX0
   21.48 +glIKDPBKJXx5Rf77MnOFcUcD6mA4r7Oyi7ke3LNWP+L6a62ueUEvY13DWNeHmohW
   21.49 +wz25pDvoBLWuUWyOYAzvtwoMgax+uaLVXVjwvV8Xrpaexb+5mD4JFrxRVdjJapcR
   21.50 +ls4iwEbkOv9i53frQ8iIeLBi+8LI00Kz56o4ztuGf5i3bjho/Ju/ubGWTLjJXzKw
   21.51 +TzculGpNUeu3fHJrjqTUO/1jkko0ndi7avdYlgyuBE8G3uDdzbGYEE04kLYmkV6q
   21.52 +wKySlTg6h7T+msv9uN7FBJ1U6vhzrRorKz/pLbLynT8zX5ZMwl0uC+UyNwfUZanJ
   21.53 +SJ6cIYWZ00EiJLipQx0wkImRGQ77viUNKoVD4i9taBLVuPJMp7E0sXQ9qxHbspDr
   21.54 +XlXy+XaeD+rr9fhyGKBxfSqGe1HJmBWvhXWSwHateLuHTGO7qn8GPCK41PMMyeiA
   21.55 +x8SYBFzUGDUBDADPapA35r7ZPQFkVLhCI5sAp6eWOD6OuHXABcRHM705zfeaxoB4
   21.56 +PZgvziedFy4gxTdYwkcN1fL64kRVZSOGlQD7/QDO1JaWWAN+zaT0u6XVVpNRd5vU
   21.57 +5QtUDGb9QjIfwpWSXDmQdrjrVJQ68sSLIogAH1itvo62hl2z/DKqnRJWQDx15tJX
   21.58 +4RUAkyLzn1HfSEuTFm0wETfj2eKJECKtEvsIXe13eWkuFPI0dLWkIpoGGVV6jOZw
   21.59 +RcZ3QqkCU7xoD3WC5p/XXm4Lpq918skMt7yrgV3IFz7XuDkuMXtIYMa8e3Zx93zK
   21.60 +p8rFv5CWozozt7LLdv7kx6lwD+oAcOn15ZQd16mGoU3q27KJRXPTED3JfkItc/pa
   21.61 +H+g/uJvN50LpYu+n6UeCvLSmTtBrGRnCc1sTOJfmLfl1aZotSM5Po599hEH3/WUL
   21.62 +PMfoCAXk8hPlb7yblEOc/cVbE7KCXCjM6/bvlzUw+tMWbzpPX5qxUNdI4Uw6ustZ
   21.63 +tIb7phJsfTNDTTMAEQEAAQAMAKwf8MKTODmrCKasL6SjS5RFjSt6TV++7+iEYJf9
   21.64 +9cAsjpfgtugRpWO2nuUcQWlsgDumLbTroZJVhwOexNaAfKqhELSTcswdCfmGyqdV
   21.65 +uY7LI8HtkmIgGUCMckMlVddJcTpeUl7yRw7zx3cL09LquxXu7XZxtpj99HDSj3FK
   21.66 +m9b7w7DL9i57WSR69fxacGTs59qON9o1z73EKNw5ia07HRuaZuBI3uIg+8ZQPBST
   21.67 +qmH5UBg9KVZucP6zUPHfb3Cjsg8c9Obu5D9wHueXRz9irQcDM7UZ5W7ZQyaHL8cR
   21.68 +RiOMOZZQYkd6AG7Gh5Ta6uhjEPDko5uIgcCmn5mCY6Jxr77A4IQDN4l6tG3xvTUd
   21.69 +8gHsEAGKKMCPhwgf8YusO85a89oSdyyBZfJ9E7G0lpkQZa3MZVura06FcAN+ritP
   21.70 +7mKt4qeasYHpSrq6JdvoqKjI0IJssNbfprz1w9zCof+g8wiw24QUckqNEVYdGr6j
   21.71 +AKXZFQvQXR9yVZJLDsnLWiKjYQYA0xjzy55Yd1QwubLiQzCysqEOzpvhLC2wTnnH
   21.72 +IkEcO97U87ALQqI7/mUkMIuIChOeP1v2z4Djb6b+FA7OL94J/3UInz0sktBKrAXc
   21.73 +qm4jpPtxNkmvZStviZtoZOfyyBj02hIqNVFKJhgkct/nmVbefMQkyEjAVDF2F1Ph
   21.74 +802wcSjuB7J8ZcT3fRM0sU8WVydcVeucb2/+TEa/YGeiRJfzBqtgvtuPSnBGP5ZW
   21.75 +u3G8Ro+fee7PqiPV8zHVBLxo76xLBgD7iSfQkt8uwqA2q7yxeX/ZQyUIbJB0xCFz
   21.76 +W9RHQbYia9KFE4V9dSnRO8wicwPCOekEKqzz9YhJQUvL/TOsGLgy9jVyNsjDNusk
   21.77 +XMTet41AIcQIQrY6ZvDIFMbUJpAub+FX4Qf5hu56lqYGjOyen7eJ1uqoZxZYOQ+f
   21.78 +1WpjcWMQ2v8vY7qPofyWzbBnBFIxJCdR4daZaOxAGa5P/Pw8pKA3Ha+53in6fHa+
   21.79 +bTzdBOz4PNsYTfEMdSGkgCwFzqX6gbkGALRuP2GjBLBvKqDlIlJW8PQ9sy5vAV/C
   21.80 +SDb4gLJiQHXBOwR8TZdT+xGwUbJMNdZlMUZvK+9B0vkhOF+CZBUqpi3uxfOVPWIK
   21.81 +HoQwlbO0yeg4bv7NxboAcs0deszqhmQ92BMOotfmPYKO6naARrNnjJPnYhJ8xzw+
   21.82 +gNfS6SZO1l6NzDxvGzalXMHPzUzeI6AdwjKkvgnMt8Kg/Uchp1PBzJ/63w8ARxFt
   21.83 +ezgC05cVvu89KSNRrd8/Pv20LGkwX5Fn/edOwsECBBgBCgA2Ah4DApsMBYkFn6YA
   21.84 +AgsJBYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAABXMgv/
   21.85 +Tbmv1/UgRff9vRETEi9f4rUYOsvX5Ay1raRBskl52JLbGmkXI3SeOjoL7wv3xzI1
   21.86 +ieIEdpyxcJNQG9n9Jfvs0qqXwVisnljRfWckmEzu0MWqpQtKmX66naOXwNJjbmnZ
   21.87 +CV+WgWHm8VsC2AF3QkP6XnunIsJHwL3yMfNrg3QA7dgJusEJ3AGG7elGj8UILLdX
   21.88 +VUDmQnPcu20aY8vNWxadUkIm2J62ahk3oeb0JqVS5SnxBd5ZWSj9ds2LE/v5Q3Qx
   21.89 +RFpo+IcNQ/aUDMLiEHh4J6qW9N/1lAPedBW6vCRtLLXworhTb7ki/+XT4Q6MFzF9
   21.90 +mEDX+DP8NLLFSBl9C50EhDle5yVjtfMeVFYczaIRHCuumY3o/j1rGS/lP/Tk7aDI
   21.91 +Yf6yfHeNJPdUzhnumZqXmJJxSOQtVm0avPAeuA6T23WLqaV9KIUhpdno4YYj/H0O
   21.92 +TbTYReoQrRLbQ0nQHRJVXMhoODQq4frKyP8nQ1DhYnDBj47oD4ZDhI+QuxiCVO5p
   21.93 +x8SYBFzUGDUBDADgdeXRNfdimkBUtMNp2LkK54n24C++P/gyJmRA31hrw/VJtk4P
   21.94 +jvUT3E1+lVr0/HyPQVcZJr/L+RO1HaYqETq0inJL/Y0o2L0Ky7Y/VRoLKBdYvjny
   21.95 +sn/3pCBozj8HHuyMre7ORW8vxE3QliQkwUbqC80Lz3tiyXBJ/0bN6skYRHdLKE/5
   21.96 +C1ou2dBDeib7xNlARcpa40tzdvPu/j+H1HyeV/VOrK/CEzFBTAWbb7IJyUr3PPl0
   21.97 +mU77BOSa/2OS5HM1sDd80MJ8pjqhJxprBxa+9gkgxUbkq8lDo7M9IsoHDEAsrM0s
   21.98 +mJXCDqP7Moz8CB7IQC8aOVtWXhs4TbTe5xg4lB0Q91GOE82Zu3j4x4GeD2IhUP8g
   21.99 +TqjgW6v3KRMo4pEYLa2Q2PXWKYiLT0ZgAvmJfIAeMzo27XVMx5SDhQd6jcVMiDa1
  21.100 +qtbUOW/34161zInSJUl3mZ6AQc48lYsdD53lLQE0RR/oyYzo2wDhUbnpy7TmrAnz
  21.101 +K14AIUoeDLsTi/MAEQEAAQAL/3vd0/M9+sT5JqMYFfalWIhB+gq48N/mYUsbkJuU
  21.102 +JTFjNEt3RWCknW5WVpWSSl2DsCFGB5Cjp5giXdPHBtmUJHdZJ3Xz+CAga0I35NzS
  21.103 +U8rwVuHsKAJcqu24LwJnPrTpRdTkbzJ5csBDbkW7dTqrRj0GQiNQXmDHlSXgr+wW
  21.104 +st6necWJ+4gN0bilDp8OG9E4ckNbwC2j3RFdBYRP3jNQ+WxQUdkWxu8stDO6hiWe
  21.105 +3/sykCIcDfVgXQt9ScKXSRXY5wpfthh3dASxyUlgM6DtA6wm4I4XsHdjrZI/Bre3
  21.106 +wTKyrZ42WnwVcFk0MlE/82uwaj5zxZp3fdfLG1b0J7raCRftBy3uYMhExKBicv7t
  21.107 +y/eBbm3/lKswUAP5aj8HmDd1MpSaaCl6A1RGMNEeo3klL/Bz8FL/QLSxPemLArm1
  21.108 +HN4x3lbDF7Ejx9bWTA93UVoGUis2uQSuuNgQ+Rx2G+Gy507ydn25tmNgPQeXLWqn
  21.109 +kotX3C4542J4Z6F+BJ4us2jaoQYA5f0ULMGDRf5VWCemYSzvJSLxk7XA2yBrUAbr
  21.110 +riUk1ZjFuEdqHTBzq7LtSxbK9ICP/chqImQuIk3wUaht1g2GaRX+R0rblxPi2DUu
  21.111 +OqKFETi3izGJ4xZqipA4pSFsmVNZnO5XvCTAbT6SCsjMlHqx/Xrkn5EGcAKkxStY
  21.112 +8Uti+i054Hr2qPDJonb6B6RESjOEZ9KhfDAbIm82MOu1o8LRKZgedKEeEBys+/AI
  21.113 ++lnimKbHWBT5NFUY9RLJsEt/415ZBgD52MOGjYX/Rne7AeGTsZrfY03D5yTe3DXj
  21.114 +U+SL9Tcl5l+0thObux47atKNfih4uscvnnz+FRQt0C8wqWRucRd7C66PFMrcBQy1
  21.115 +1mV2GByMvmM9TVmdDiV5OCyadTsPRfuK12O723XLJ//6WYJVTZO9+yy1v+Q3I8N/
  21.116 +8eFbqlsoxMzhGvqt1iVpm5fx8yGaP0dndPTxhK8FW3DVt4HOwokw5tvA9K/T1+UQ
  21.117 +zeIES1gqv20RZlcIOmMK4AYOAIef6ysF/RQzXAdR7JwQUYTgE4SAt1n7EwBaMCVV
  21.118 +16vo5O2r1/z9G2vkn4vbydF/44XFEcC0mlWOPtVhQ39MnlAjx8wgWkf/8pIYu+Ne
  21.119 +JIrdidMe0ecAQV/z9eQw0C4Wag/Sjp0llPHOiwOSGtOJ811xc9nlSKNoIJvCPU6X
  21.120 +CI1x1ue91xNyPA1i0K/VwyRnYzDm2BEVQTYymoHVf0qi+g/Hs5xgU+unNAJivbbL
  21.121 +xH6ZH+TzLtMfFmL6oWRrPz/6c+1Dn9OtMd9iwsK4BBgBCgA2Ah4DApsCBYkFn6YA
  21.122 +AhUKBYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAbbA9KAE
  21.123 +GQEKACcFglzUGDUWIQQz8QOZ/vi9W3qvpZTc1VW2BVreIgkQ3NVVtgVa3iIAAMck
  21.124 +C/9Enlxfu0GqWcOdYKxC6xoNoFhFrCrTRAwGfS8h8Q17y6gelstSw+x6Lh5PYOHe
  21.125 +/hkf1U6nKkTcgZeKuoiU/JDkje+G2UDxzc0IDl3bXp9HSoplvSdlmAKGTFORyKg7
  21.126 +bhScBzpYbmdGxfmCxBnbFYdSU374MuyXyaYePExW7m1kKjWFQvgwGbTRj+/B342/
  21.127 +uhx7Ixl2GgXPvhFT/qkVUf7X/iUIvtT73xj0rVVL9Ox+KjgLbuG1dYzg2blptXbw
  21.128 +O8ttg+SXrycoVR23IgMcll5vnqEn0iB33TCLxqRxOwa1Bg/TyBaZX0qK3CjmNIvW
  21.129 +QLJ554HC3xKJsPnDg9kA9FDYO/Z1aoUm5TST82KlOXQQ8aaT5zFWms67x3C1WX2+
  21.130 +6kJ+Ox+3N15IOZE7ziMxj+taKxtdGM5s/GWs8hlWydvidz7TUi/r7OgLtT/M1t2b
  21.131 +iQQj9wVSE1b4T1mC+zGVpVf9EC0PJDkedMG4AW2UhsLY88ShkVA1J1uTlSsKPsQQ
  21.132 +O3escwv+JeoBB1Hox4STOE17XyjaSG394DeiMaxdizjGtMBuQPxyeGt95IQV9wit
  21.133 +C2qVOrfB8RjFMLC30vKrS85tynYp+ibqOa3387YvvRujlbV1FMnRFs1iUGLTwftb
  21.134 +M0L6ndqq2T5F16j40QWOtgXU5LKa1wvAOIHQ5ZhtNoMggxP+YYjoQjimrFUfPTOW
  21.135 +Ot+dffoSQgK3elDNbzK7PziSGg/WwCmYrJOTVu5purJWw80rfiaBrpgiJLAU+jpQ
  21.136 +BC9HkznSBxAGdTNaqOGrifwIBMqBZt9eC+sDex6f7j1Kyn1y4uExy5Sk86D8N2eV
  21.137 +LobkSc7ri9rTsjp9xYq3eauKunnNqz8qU63LKt2CBFf4/y2fdBrGXV+GuSNeYDHy
  21.138 +c4fFeUdBI8/gRq1irgU4BGoMqG/RgxroKc5ggvOj5Wbd0e146ksSQDia3/a1s1hL
  21.139 +rnqRKdw5qN5peyUmOgZWW4w1NMbT0oRdtznVurwKvtRdd2WBzE6IPkEkJXO1muVF
  21.140 +iNlLnPZz
  21.141 +=i7QC
  21.142 +-----END PGP PRIVATE KEY BLOCK-----
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/test/test_keys/pub/hans@xn--bcher-kva.tld_-0x08AD6E9400D38894_pub.asc	Mon May 13 19:30:36 2019 +0200
    22.3 @@ -0,0 +1,77 @@
    22.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    22.5 +
    22.6 +mQGNBFzR6V0BDACkJ2yRZAaR7tg6jAC87LLICjd39xnD/Ra9D3Elld5QTHZ2GXw+
    22.7 +8v1er/ZYcvS3JPZsjDvIeg5bRV24IpghWyfRvjBivLlAV9PCWSpfCqj0xnzM7HaU
    22.8 +UQbPg/Bwtf7m8A3YC16pBIbmGUHfIL6LUY7Fd4dLKu1UELuhKn/Tn6X9YuO4Isah
    22.9 +w2U4lbobzFvH7PKkBuG3+sYL7JhE/ArDTIWaSoszvPtxTg/hfSj1rZmfYrClzcB8
   22.10 +aqoilhmRdYX1DNk4c7bsg513XirqTm0lJMK23hOJithBsGoC6n6Tm3X9NC/a4hmE
   22.11 +Fly8U8Y3wW26WUUR0gPfp16c5GFhLlOuRwOdO0D+WnEOnw+Aq1IRd+LtLq4psNRv
   22.12 +D7dxI299tBuybn26fQAUXmMqF+MSOqyqKegi6IIiD1jFDAg3t0rSu77pphMm3ANS
   22.13 +uuTJ6xrhnS5YwRQ5/czJu6MFK33ycWw/6PLnaEgrNS7XjHXsgSPgjoEPB5+hAwDn
   22.14 +roW0DnRdmk2HhnsAEQEAAYkBwgQfAQoANgIeAwKbAQWCXNHpXQWJBZ+mABYhBAC1
   22.15 +u2dpsfRRcFRF4gitbpQA04iUCRAIrW6UANOIlAIVCgAAmOoMAJDdl76LH1oGbULA
   22.16 +Lh0efmpkL6rxo/sneOS1UUWjbN2/+ObzX4n46fOA1i5f0yYmYS1cQFn2iDuutmXl
   22.17 +hT4EUCxTNAdz1xRmPKRegn6rejXl2Gv8jlOSgMMHKqcz3dJwPwOEB9YJTQtLUUBy
   22.18 +i/1FTGFO0CC0QtBm2yTV/U6rRucxxXt/iT8WwXOOucMXCT2RDuhXeUDP5xSWazAr
   22.19 +Fn9lKQYNnZH+jOib/aTEhv61Qg7WITWbfhmbvv9bEYvK8mVQJdtBpTqY4uwdT1cn
   22.20 +s7rA7PjXA2ertXE6YjYq166aB/QKJrpD1XD2MoVfAqObJl+6UCA0dy5sCl3BPyRj
   22.21 +e6HB+AthcMHXIDbSeJM/RCfnd79oqZaHDWvRL/9CdoLYscyeuNCdN82fV0dcIHa9
   22.22 +GNOiQ16l+6yc/FY/afOd/9qnbAnAT8paZtEQvspoBwRzDrkWMZ5BWDftQs1CysSw
   22.23 +R34Qbi9oUTjYnmnkunWGzaTPIWgYCZUiDV9Jslj4eXz6h0b4lLQdSGFucyA8aGFu
   22.24 +c0B4bi0tYmNoZXIta3ZhLnRsZD6JAcIEEwEKADYCHgMCmwEFiQWfpgACFQoFglzR
   22.25 +6V0WIQQAtbtnabH0UXBUReIIrW6UANOIlAkQCK1ulADTiJQAABRkC/9eUMSklNts
   22.26 +SrSX5tKj6XoY0UFZspM7I+oWz2MaZhZkQDelCYuLtsOf+lQ8XCLs0riJVeCUrl4j
   22.27 +WDzwygr1J0xHfRxOD1I6bMKl8fOpnK9izQqCHA5exRBWzGcYIOXpva2fUoCQH+jd
   22.28 +F+NtT99pjaOqwBdbfFREHFlLLqtZqugxwRo9+g6+8tEusLIK25n6ADzJ2whqPc78
   22.29 +AGi0dOso1GkaSALvhkuFrwq4KI+CBZtrrnzsqZho0TtIi9aYNDBC6q1nNF4HDa21
   22.30 +KDC629SkqqyslfeI0Tr9Vr9JSMoeQiX5xzHtsRgr5w0Evw0wBhZHLutEJPkKim/V
   22.31 +gmrjwA/ManpAnFk2a8tLv1p2tiqCgG6qQ4U1jQ87i93ck1XHuEf8PmSp0FH1Xv90
   22.32 +4Up+1SA+uh4osoDX60zyQXpo8OY/Db0RpIEyaaaxvPs5mUm4K5K70Vi5qPmITZ4P
   22.33 +pYV2dVB98vvJZB6wznNDLFu9fq+52juedsPw5HCdE0OqxzTr4Y0N+vC5AY0EXNHp
   22.34 +XgEMAOPdZfhoGSCM/PPNikVI4TFgYLkwPBKGwQaYIj/8YiBPNlBlpavDkQ3a5sYr
   22.35 +qCdZxH+aSdCVwot7ro8/KuoWaOiUuHIuOOwyA2l1VkhUNxqM+exuhouyXzDGh+nb
   22.36 +UoWK7v56f/sDTNr8bsTIQa3eQ1gNLk5N90fAvyadj4TPTFaYihfprdf7SXPSQjgI
   22.37 +vidq/W5PJ80+oHqTyPubtHsqeNGc2OsnXebxgw/l9nc9OzC881cSkfErXQJnKDhs
   22.38 +/BWTTJ5LsvifzPioL6Z0zYIR/uJmq5EEQk5HpfifIQbXTAxcWvdMJa9Dxfh2hyqQ
   22.39 +hhzU69UkkU28UlhtkBv2JuLKzdO8h4CTeUImXN3QRtzriEMf0s0M+XfpULPSlima
   22.40 +TI+gtpk5LFuW2DRgRRqjOofVodxSPh8Pp2kvgjdmlYYyUx1hm9wzjIZDaRu5ZGXi
   22.41 +J4zus6O+4n6nvlrw/Y5HhpTP0DRMnaNARdaqJ8RBQyoHQLS/tXDbOSvAf+x3kxiD
   22.42 +d2auqQARAQABiQN4BBgBCgA2Ah4DApsCBYkFn6YAAhUKBYJc0eleFiEEALW7Z2mx
   22.43 +9FFwVEXiCK1ulADTiJQJEAitbpQA04iUAbbA9KAEGQEKACcFglzR6V4WIQRnjffE
   22.44 +IDZxt+xcemdAF7Q3TXKqwwkQQBe0N01yqsMAANGRC/9EFm85majTBsYTpZNhG9Rk
   22.45 +k12JMRjGjxg7GUR/DYZYKXT9BD4SHxcWHomdzhXvRSLDAe5nRgUVfEDVzorzOFwG
   22.46 +Sr6fkQww9NMIX+WaoXeqpssYbt3DLTJV+vLN7v2a/PbiYCEPu9pneb0h028sgp34
   22.47 +shZoPTwZultNz5Q0JvuI9jH8s3beU2z+CtMscrUpNYyrhPXVJKt15PyPd3kDHdSG
   22.48 +/JG5Yv5Ep93xYql+Xf1ls+XuVBiza7KgpPdHIwjroQpcoZNjZQ2NsyjY7IFjdQi9
   22.49 +2M1W3zSQ+/sxXME5CVSQHsgRS4v1QcsUq6AgvaAGxZ0mb+2fGb85XM6NL2Po/VSr
   22.50 +BR002H2deWki9BqJ/HLSbLRIizq9+dFUs4tdQ9D4yaLiaJ1WrWmVRTI/Gsl3ebDx
   22.51 +wS8dljbFVGoidIIC0UeQDnSYDKR/9s6H3M/bG6MR0yNJVP/91SzxbqBMe+pdEwzV
   22.52 +rGkr3kIDtQtljvukcfZkRjFnqPFKId82EOTUAp9qqG9fnAv+MQnR7mnx5tPUF6Lq
   22.53 +iE9RwjTZg3otRY6qVEe5vi7a4+utgBsu1j+7qnjHts7KuLePmJqCVUYKxDZiur16
   22.54 +MQP/Ztvn0eLQ+0gFwGwhH9Win+sQANKxyK5Nvqh0/7kkacs91r9e3bgJ3Vlddr0Y
   22.55 +j/hkRC2qIxlmx/zZnivfJix+lWJM+Wmz9dr2QorQ0x+ute+p+Y+w7PL7P4+kEipW
   22.56 +IeRXgjM5LzzE4GTcB3pFZvM99BpuQjtR8lr9qSL+MovGtCW5CD5wETiByWcHL7Hc
   22.57 +SjGYiODRO5xk7mMeRNHBSYWdzKD59DvWwOOKU/M9030rk0o16lUlLLi/c3iAByC8
   22.58 +48hfK5y9tW/LjmVBCB/0cgGBK7mgUpfaCfAbD2fEHBnZdxABf1difnoBVUBGpfli
   22.59 +86AxeVyWdQyb0kJPMEfIi3Sg+XNZbBgLAtf7xOgtuSriZHWkyJ+nQQuu+chMbmUD
   22.60 +HYi8HcP9TNl6BHT17owXbxeoERmfN9yf+KJcJCOjlSF6WsohuQGNBFzR6V4BDADw
   22.61 +cNITPb4DDObd3RblEpl4w4Yyn62zUMZmialJRLyi3UfbAP5K0QlzivLFnJZFobNd
   22.62 +GIluV3lapzErbaIw88+CaJb7mPY1qaoNRmbcbhA4XMM1zXS6uoHeM/YWpRxrfo5Y
   22.63 +drq30hADLkcHPbVL26udRNw0kGFrvELkGW3pSbyjxqHZ6p/8JuU0/vlyqrifHCUS
   22.64 +yP5GHrgqwj1wtV9oKHtclQwPpqmFzfZGo3hr2Pz34ddcX5BzVeAWYAUjzSJLgq/9
   22.65 +vp8jQWJN9SwTwrC2uAVTfoLD+Mzgn/TcV04pmjn/Tfoj1Y2DkqcMQphgKx1ukHhn
   22.66 +Gkcua0EC/3YOetdn4RhklnyKN+ezHbNmSCUDMxKPMdl3e/i24CVv127VDtgqyPT9
   22.67 +jNYskatp5EEkbVmDhk0tODbRl8knNYSNSGoCXDF8qYH62FEv4Fg4CUcMbLVg8Ch/
   22.68 +2xDdrMhFHyCQX6p+VrBGfDZoK+zUT4Qa3nYERXsI93bpk9dj3SWnfyTd5CTPZ70A
   22.69 +EQEAAYkBwgQYAQoANgIeAwKbDAWJBZ+mAAILCQWCXNHpXhYhBAC1u2dpsfRRcFRF
   22.70 +4gitbpQA04iUCRAIrW6UANOIlAAAAjsL/AwrdiMqx6pImsSYZi6+pWCwn25Lir/v
   22.71 +dT2INly2kx3KNym32IBfs6QIeCYpPhReHSJUu99gfB3UiMZelYzARcSn1b+9qR3n
   22.72 +W02zmd5NfDI/RX9oiZsYYw62x/mAvoKdjTus4gq30EJVKB98bZBftCl8PPSm//48
   22.73 +5WDN5zqbd1/KH+9HDCHZW2Yu80SOhGUc6F2pkSRkQh0YoOFFjYJklMb057BPQx3u
   22.74 +N7hZz/Bk2lBGQzg0YHBpa+/UIKSW/Y87PvJrjK5wG2wP0rxNfZS+Ph6+dYT+E7NL
   22.75 +xnlqPN8hsYxpg2wOQ372DCQcYhcyh2bsyFFjtQQb7tYGuM0R1myBa+j5ZEiPgfbh
   22.76 +zmgd18Z5iOhTWnk/iO+Aknt5dIVvqyRQrvnfmVN5xgmGAGT3NwMGBLTyehe2nATA
   22.77 +sq1hscxNXSE/x+SbbNStMT67Qq/lEyVrXxb1Xq6kTfN09f91oDdVU/9AJxiSzE56
   22.78 +a5vfMqJHXMK5By2UI4kOX3Q7oXjkZBenzg==
   22.79 +=M4t9
   22.80 +-----END PGP PUBLIC KEY BLOCK-----
    23.1 Binary file test/test_keys/pub/pep-test-android-keyring.pgp has changed
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/test/test_keys/pub/pep-test-keyring.asc	Mon May 13 19:30:36 2019 +0200
    24.3 @@ -0,0 +1,268 @@
    24.4 +-----BEGIN PGP ARMORED FILE-----
    24.5 +
    24.6 +mQENBFV4PbEBCADTmjGDsoti/VPoZ3w2oCjLBNq1jWIGMkbiUgCGUQjVsNrSZ80U
    24.7 +7RmA3Pcu3hhiVQNBGA32vL6NPhSJPanVd77s6XVZg+Gq7llbGGkuIxSkJvVrWzYc
    24.8 +kjMsAInlJ8Ll0kHHbgATOlO5OtQ21bLCfWZPSq74HEVzQAPtCGYFvOgpCktKTjms
    24.9 +GXe9ysiYN8CEWMVNbDqXmvFhi4UifpITeQBVM7dtlBw5SoeLZpsHIlKF5i5WPkNw
   24.10 +7nuMag/+lRpOqvPumhOmqybWHuAR/Dq0pOOPh6BzZ4OzOBL96aWUe1dcnIZeBEm8
   24.11 +oRxYC3nN95YsjtrLK4BQZTYDTzeh8FIccsLdABEBAAG0RHBFcCBUZXN0IEFsaWNl
   24.12 +ICh0ZXN0IGtleSBkb24ndCB1c2UpIDxwZXAudGVzdC5hbGljZUBwZXAtcHJvamVj
   24.13 +dC5vcmc+iQE4BBMBAgAiBQJVeD2xAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIX
   24.14 +gAAKCRCpQR0Xb/AOl5JjCADEBoordVBCmphG6EY+u5yjj/xeQN4Kc1Rl06Ii6m18
   24.15 +4hnF/osxnTicr+A6Hpwf8whXULuSwXvfuOsVOQdIc2e+1zrecTqyNUWuRs3T7uZ2
   24.16 +5dvROg1XZuajMPf3wh5lX2rPRhOt3UNXJjQfc1MSYXpmT+PoqFXBzMqJUo2DYcw6
   24.17 +MSZekoWkIzFXG2s2YNwILwPnLnMesFtzU6mn9qhfoFsQA6aku8AbG+SNehNZvGuu
   24.18 +UiBmu+4UYNoc/RJa7vNWECv9qZQsT820CuoOZS9MFV7nQlgkGoPerlGXil0vkOG1
   24.19 +gsuQD8QkuaTQpn1vYvRcC0P27qLfrqlPv2Ih2hoIV9tJiQE4BBMBCAAiAhsDBgsJ
   24.20 +CAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCWV9iIwAKCRCpQR0Xb/AOl4oaCACZrLPy
   24.21 +c/lGHNJ8TT3KxIls/Ss62nWq4wB7dura+IUPVqLMNefJamQqG4BSGDR+WhC6Luf4
   24.22 +K5JgauVbHbIUm3y9LLqAJunePoOAQEQmGAIcuJzHM/IKXJoTdudjT7FJ+dxjOHLh
   24.23 +zYOIJw6I301sJUx25LxxTihj3ClUzL1uH1IrH3ctD1yL9lPIixQ3JocGUYZsZ9sw
   24.24 +CWlFzhYelAUmJuINJtKMeWkFvkVQ9xMU4ZGU4RGFdYcXVmSii47dNQEiW8XzcQ6D
   24.25 +TFCuaS0WWy2tJfRQSlaOCBs/DYtlrWWWBApinb35QVWNyAmTwCm8FlvjFA6kr/UE
   24.26 +9VMfP8bhbhspQLihuQENBFV4PbEBCADQwKB97t2B2nweprfpbH8QgLCzJYaAMrpc
   24.27 +aUaJqm+J3C9eaepRXTXGtst1zaLbooG2b3QHfDzI2CEYMxO5ynmmSBOe06VKw/Pa
   24.28 +gBzK5ur/eOycl0ZPFSXdlDj30BQPvRdJvLS4OTMdoKoGpsZDY4hOYj67oHo3TFtr
   24.29 +LJCvZruPARkI/pXiOX9FqH4wquNNaYW1qwk/Wq3k/gOMwp0xjvc01MbadaiiVquJ
   24.30 +k6jjPrd2wP4FYxIADAllzMpwFAJSWvgCfmqVbukYOnaCp3QRQXQkc78TdqGXbD5u
   24.31 +wJzkxxiEsMmiGT+7RDLIKwXheKmmGXSwgi8m+EndUiqMTvOdjyUBABEBAAGJAR8E
   24.32 +GAECAAkFAlV4PbECGwwACgkQqUEdF2/wDpeQVQgArnfQ7uvG0po/CPepbrdytI2n
   24.33 +63U5dm/MFMsvXpZYVYLO/mROc+akZCPwS0yxtSMKK+tYM9leQx58r89c+K1GeZok
   24.34 +o7xziwmZbt5zEITiJp5L6gg7k6CczskPMx07gY8ooscBC3cFJhz1A0o73BKPR7J0
   24.35 +iupaNmI3sTd1/RNQm6573kGGwc4m2bcQttvN5ox8yimn2QnK3D+6A+Mmzi3Rd11t
   24.36 +F+tAWJIsfaEgDJZn9mOdUkV2ckoSk1K5PptpXSsKLOL+e2WuxSMIr8AVeRqkbYYK
   24.37 +6UzX6qIgQIrMOuaXqtRaNxNccnzIS1YtdtYERSnTaBotNp/FF2wfI7BNFP6r0IkB
   24.38 +HwQYAQgACQIbDAUCWV9iOQAKCRCpQR0Xb/AOl5ckB/9UBwdhKEro2dSkE23KY64I
   24.39 +/dNXljndLOHK8fARd1B1LWh9YHOXHtY4+h0TC8PL0IsK4j5PK8H51XqhMKKVYDVG
   24.40 +lhLUQp4qcDNcuO4dW6dS/HqAfARpLSKgwEEWW1bFzDmiOYGnQjxuEsFPlXADFTws
   24.41 +YqVX3lvZO93nU0fa5QRK65nWiMomC0Ym09hZuznvk07kyZtqAlSNgPUQNADpTJVH
   24.42 +teDbVo/oct8oRqo7ajO+psOVTaQHfEeHiFvPo0/MUWGeBhL96pRHIeO83cSipjh4
   24.43 +q46bEcclS/gTGHtFweVOiqRnR4H5YEjurCd84h8zF8MAArhxBhAtbg1nYgeHjkKX
   24.44 +mQINBFh7zckBEADIBrJVrvyjnLme7xPd45q3iShb+XZO3lYmLyaIyK5vg1xaxFv2
   24.45 +sXS7NN2q5/CUmM+Ab2+6OSOzgxvMpJ+HTSn2F6Hv7X7LWSlF+gn+wz4YlUwh17fv
   24.46 +I5UVtMSxiMyB3/t900g4LXOfOOFixpcQz9R2bsSFqBJt7aqkA5YlZxtBsCZ4UEZa
   24.47 +3b2YnTPDbwYdA1HRb1f9jEEMSpAxqmK3DF9zlSKqeJz6JX6qguUlTcOIMOyWVtKl
   24.48 +9RTl3UZrfg/qPcgilh6pK+MvuStdRdLQ5e4RPFH8G1X399RG7Ce7hQMysajBWv+8
   24.49 +ek0kARqSh6DvgUIHkEePxHQ9sKZi+R72i8A9PG512veYCRw11DzpuBbtwBvN48nz
   24.50 +g46d7+qtN8tYeylGTNtRQ+epbfotTYSPqjgkpGOTr6L36ushKM2MLDOhqjoJF+eP
   24.51 +5nbjbnaZGniEZym8I9X4iTm3/WOKyqhe2lp7UnZYzDAbkNz64miC4CIwomysZy/G
   24.52 +1VOGzeyo5SAx96VXeaHtnPIVzZqGS5VaGP39cl9R2oYW0Ur2dwHrcy2gH4abyXVA
   24.53 +hQfbNOrB0HI49cKR7xo5amMqS+SxnDS9CvEjAKi9hIHAUTRKj6m3C2o5t2ROYZZ9
   24.54 +lWTBIts1cGwMu1kVQgGYnnifHpuF2WUWVShQjSzBnW/OJUl63gW/1JoxRwARAQAB
   24.55 +tDRwRXAgQXBwbGUgTWFpbCBUZXN0IDxwZXAudGVzdC5hcHBsZUBwZXAtcHJvamVj
   24.56 +dC5vcmc+iQI9BBMBCgAnBQJYe83JAhsDBQkHhh+ABQsJCAcDBRUKCQgLBRYCAwEA
   24.57 +Ah4BAheAAAoJEAMT2Uocy8fXLlwQAITvJqBxGRTtuU0FgFLMvq4OZZPhumUGjhi1
   24.58 +TClxPQT8+uF1Sl/pn6/xgW0Tswhx9XmhzoKipFmr2u0N9u2rcS5MupoDarZQe7z8
   24.59 +AaxdwMmnoDlSdttTsE4nj8tqx4zf7YI4rSJqY68iVD2b64pOxkxgQIBhc28t9bRb
   24.60 +/RNLaajtTwLlw1TVO5zH7sKKcPehHXX5avomLDt5QKpN/wV4f9F8pUfoIw1q9vjL
   24.61 +/9fUQmWnLsnNfVVyB6gq57D5PLDa+f50wDAyopzgdY1NG23L+4HCb4EUjUtQXBpb
   24.62 +jD5QytSCzT2a0Nfmpj9e6YmljcyeJsoWvv4k40Ob8Q+ZWCBc0x6SjYAHbj1PjChW
   24.63 +fGHl0HPhqXcL95Hg4q8TTXMtrmPZ3wROUxCDn6/O6NYbCgebTmEcgKw/DxdTeKFr
   24.64 +0JLqR7qRp1V0h+DADju8Buv7ticJw4aMy+dUZgwNheyMYWYPCujY/Yh32z+08pg0
   24.65 +XcAqKCQC9KGlhnaulPKPdQ3oBmPWFIflD+gG5B6pNrlQWm7P6nvVCslf1oLeuIUM
   24.66 +e90bBmmuh/b09zG/wyM8vkDxopQakSn8FwP0MyfOrmk8MYXFfF298xpzLv2tNq/5
   24.67 +BROVov6F5ewEdG2MQ/G83pwzwZzrOwl8wUnPKM8nMoInUXi07Lnd1yprOWpi/TOj
   24.68 +O3PyvrbduQINBFh7zckBEADXCOV468fB9CNKZSh/QCtX560vOCKRHMItx5ovx7QL
   24.69 +Ti2TgwoO7KyhwgHTm1SARug+w9/jyYSU0NNdXOtKnrKjr8iwIfE3RAL84EZSDvK/
   24.70 +zXJp8u1gmgAluzAAHk2NfFX4WFtASsmd731wNAb82URbQg4AbVEmcMI9/WXusXQv
   24.71 +7Vbt4lw0+JQCuI7B7comwpdMcprOQVt3WK+iznp1SJWZ5sxzYerzMO8Jdx34mO5o
   24.72 +UiseSqV70KIiDRwn4YX3DaIINrNvk/fjmIyDEQc6f/zVAnSKnj3tSOTRCgKEWisp
   24.73 +6D5Gn8Y083YW+5cgXJAazjuB2ZHdnAEXJrNIOV/vfnU+GOMja1LjEVt7PX0pAzpD
   24.74 +RE/bjgByHAkpw4nnwclJ7xwnvcHCrXcW0OeaHvgqY7D1i3b9NeVbM0rfXrZctPuq
   24.75 +OESTJbT+Jz7ZJ5oeDRzgqJ44BzTrQ/yRkeHUF9dN+16bjNOZli24C95fF3jIthbt
   24.76 +8gOFgJW5OZEVz6w6AaU1plhGLDBZh8cqCuYRqyi8jDCee4SNrBlwcLMzzDtKPguh
   24.77 +gdQzleG8lHxXqVY88HNYDThhe1ZWoKkncP2O0sv0WFhu1y7qk8BKwang9UWwjw/C
   24.78 +3MRvz3nzttC5xcTLMZB1WLPQrE7GjDT2zmvvTENNX/VTnVeu3JHL2yYAJfoiCgBg
   24.79 +wQARAQABiQIlBBgBCgAPBQJYe83JAhsMBQkHhh+AAAoJEAMT2Uocy8fX5lIQAJ1b
   24.80 +al3rNgTJ4PsXieFyiVXKbo+DuuDsdYBVqVXFvwHGv/OtzyWnv6DCeBVAsQLK6urg
   24.81 +a0ssZuHYVAD4ECYY7ELDiFRn8INYNKh1bZvqw+rH6QJGbZnO1IL9FzaeQAw13WBm
   24.82 +JFb3w4npEVuI0ZDmfPYAqzFI3ACEwlrEYbGa2IGAN+Nz+Z7a10+PJk86wdy+bgPQ
   24.83 +qAMARxo+hzeLfFb0WP3EVOkWi/meMNyOK19K/Tlp9en+SFPvTDeGiu0PQVTH4bOs
   24.84 +q7Hx20zIFAx4tOGZogTWTfOhEc9OAXxgabBPjizHeqU9JUZJe0OWGHDYLwfy2XlK
   24.85 +oj7BVS792QmciNamyBXzwtZdTayxH16QShHKox7N/mMhtgRvTbIAAxtq/NLKbyyE
   24.86 +XnlKEuB8BmyyFVgxn4D2mR3KIHkfQ1uUYlISkKc4WX0IBQa3UZnHApUxewEKMn5i
   24.87 +F53r1T4Gsf/txrRs+El50hUhK7yLmtuc/fBscFz/LfUZg+iwAnPlGdXST9cvP9WD
   24.88 +MfV389KZLXSSsZ0lXTc1FjzEuAreZVtIHi+7vTSq6QaONF665nZRfdGuU+eBUxZp
   24.89 +jGevGRdfkEjnuIXM2yqPo2t4vV5AfGPneVKCzdTrY48psiuRyFpIlMs3D7BfcK9a
   24.90 +x77AhiRfwLzS2B+UJsnfUe1qeasF5T/JWEazo2CSmQENBFV4Pl8BCACuukQLwsHf
   24.91 +tH5jkVsSL7COFhamNsEE8lZ8MG1f1Rx5ztPuZTnaYXyWODgpj2Bxz0TcP+Q17GbL
   24.92 +Kse7TWD1k9i1RzLWz8ZSCLYq2TtjLWPleVuGGWeqY3tTWHC/nFbivolNPA0mL203
   24.93 +8TGdBolPaZiPZ4P8wuQVYNfDqi4utcezGDNS8OHhEPhfyKKoSM79HLoUPc6xsfim
   24.94 +xPMrylI/i8bFvfDYz5vmydefvAxNhqjLH3Gmhj1pnInsraEiyh7Y2zAxCfr6hD9n
   24.95 +ky7WixBinKFFhQpcUu1o+Ie6UGwLVbTyRMOcRsobyahqA/m2HfDRj1Y+n8HHqsQk
   24.96 +B2BtmMYXla3jABEBAAG0QXBFcCBUZXN0IEJvYiAodGVzdCBrZXksIGRvbid0IHVz
   24.97 +ZSkgPHBlcC50ZXN0LmJvYkBwZXAtcHJvamVjdC5vcmc+iQE4BBMBAgAiBQJVeD5f
   24.98 +AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBZv/SIycLuOaR5CACj3E6y
   24.99 +kNqjGS5PzghYfLJso6j954QzLwOozTzU/3/HWH4lC3Jmfr0pGI51KZ6Xevrp3N9S
  24.100 +xRqruJCFRtwNeH3ujIgDh/UHCUEsP/+d74SOenIBYGUKE1OJmh8/LQdkNSc6JNdz
  24.101 +JjDWdKeh6cAMFvWju/Nqtl/l0FGspQU9dmCMtzkKgmwoKZW56aEVZ2lTxqNEo1aQ
  24.102 ++lLrNueBq0/Q5kAVEzUG7Ufm19wXjWenEMeeElX3UAGudLJuckx7uD8W/yBwqrRA
  24.103 +baCSeZf6RVBLz96ekjWrVfMnmjkPuQPPt5cs98RxQTpxk7b6xLaWXymhA6cYU+FA
  24.104 +W4DpbjfJjMWIFDcKuQENBFV4Pl8BCADKQ2SV6gjR5N69xVdiCaefjwobrXR1niuB
  24.105 +HBNTXMJwPk2xv+e7fY28RK1BzODYCzBhpltvRoCcJi9S7Rqyz81nbxnw/1TaKtn6
  24.106 +dDDhZPVHjN3vasDueM6xTEfEihNc0Owf4wz9SBjuredUVkdTxU7FxSgVP10dOxhd
  24.107 +tkjWjGW1DF6WlYA8BAIEdbpoheJHz3NFkhPQ8Dlzo7Ioe2t7vrTztcBX11o2e+FP
  24.108 +Oq1SmhEr78wbROAyCVAXK+8qDh4zDq8iAMZK/KnZrm6pP00+iBRcb+JQgn3Gn+hU
  24.109 +0lgE3YB9kBJLeWaHxEPNnnNNvW/BMl53ctf8Ip+pzpA1K/S23KU7ABEBAAGJAR8E
  24.110 +GAECAAkFAlV4Pl8CGwwACgkQWb/0iMnC7jlqbwf/dP4sXDRiR5uVMh5WhOn1S8Mn
  24.111 +HZhLWAQ6fI9/KxggCPhgY6zAgszPMutzBsQlV4P6QX30d99IMJrzGYYxjN7Z6fF7
  24.112 +us9u103+GTzGQH7/47JG0eSTSaKQvqEaN1+6M/OBZKcwNW6xHa+lhIS5nJGV3Oey
  24.113 +/RFQwucBujQbtyjDN3aGshwqzhJXFBlF3RqFzLxuAJmeOVedaKvdPjRhgFuxhkic
  24.114 +UhVp27qXQCpDpkUkj9hb75yCE6pAzopO6s65yHsnFyehwgyMrfpTPlPM86B1LH4I
  24.115 +EwSaOrEJSdHnnFD8nnSIjRyfra3dsI/RVNmYX8EkMGICzoR4lWcYFShJQM6QQpkB
  24.116 +DQRYHG/IAQgAnvQ58f8mqiMirFeBf2WVk+gIfYpKw55l+vanCIRZJu2NtZPzHlZp
  24.117 +vMRQvLpgrUk9cIWvnL6bzptex2Mf2zvCHqfXi7e9ilGsusPvCI7yLLRahKFlglXu
  24.118 +IDvR5319s7BB38D6u+ePo35dmzSSgdSXv/CeKM3Vv6gFr9exvXFpWxQRi3xYk3f9
  24.119 +RBNMya3K/vmeJLjM1U2hvbelPjMF4VKj2E+kGA8T6XFPC3qfi2T/z0K1lnZx/Pho
  24.120 +VfhzZn62eupNH5hH1r6pUE/GT+rv7+1o6wZnNdJgX8OVOYrcJd5TGpxbXPEaQ/ca
  24.121 +lICWPN3BTQXZlYk0W86Gtla1TzAIdwqMiwARAQABtEFwRXAgVGVzdCBDYXJvbCAo
  24.122 +VGVzdCBEbyBOb3QgVXNlKSA8cGVwLXRlc3QtY2Fyb2xAcGVwLXByb2plY3Qub3Jn
  24.123 +PokBOQQTAQgAIwIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheABQJaADefAAoJ
  24.124 +EIe93/tCqFpCnGsH/3tBl4qS4M8Ttku4NWC2an3QOlsKeid1+k2GkEoJuyuyaudq
  24.125 +Q80ZVxIOdQzOJ/FdvOz3VudW1i6HXqQ3uVITswbRRXI6Pf/ZzIjFkUGPMgfyMM/q
  24.126 +ms5K3puVJWt4OhrOfU4vykNqUu0oyTBYL0STdpRyFo3LdcDDZyGPUWUeo9JbBdBf
  24.127 +Yaqm24EAgmbE7MaV58124oDNJAR/dSoRK6WqqXfY6N5TU+nO2bIJiYExpexIkv3m
  24.128 +P5notEf7mr7ZmLsDoZCZS1QARVUJEGslx3cUS3tSrZmoK4bu+xpTSRjRjQEvQpFz
  24.129 +Nj/Eakn5p+fYwlHunSXMJc7/DZgw400efQi5BL65AQ0EWBxvyAEIAMT5UsIGF7Pp
  24.130 +U71Ro8n6vl/cFdf8PxlqT8GWlCBjz+2A+mjALu1Wv0BC3N7b5sdQsq6a9woRl5+F
  24.131 +bgELvaO9SCwIU0BS7Var3poQzdgFK0E3nLCTYi/IGxkHolODV04ikpfFsTE7xJEZ
  24.132 +0pPH1rEcqSK5u329+vllZfwwYRdsR8n1NzoOU0BVT3gr+mUqAMYRqvGakzF6agnO
  24.133 +J7hCyHdpJMEA3fhqm6zXKObANVm9bu1c99CUCV1SkpG9NbDrzMzS2F3bF+9JDRkU
  24.134 +0Lv/FUNtAbo29x19ElMxhITZ7jayDhMBtYbfE6/FLEhnVu1zZHZm3KXJa10sHBs5
  24.135 +PDHkES/LLj8AEQEAAYkBHwQYAQgACQIbDAUCWgA3nwAKCRCHvd/7QqhaQvCoB/9q
  24.136 +E0g7Uy47rfWtDNym9xcJUVfAgsHhfurN4kJAfRsgbDG8+r2bJcUF/ouPBhSzsFU/
  24.137 +q6YHmkss7LEWutYwzLxluSUK+jQBLmaBryIktWtQE4AFagcDWxEtvTf9czE7Pnlo
  24.138 +iLbBNuvoAmmaQyBBT8jlp3MiRATW2GQLfE3rW6gfJI9ofLTHQwWk1SG+J3BMeQec
  24.139 +2zIUR6XdZGAgujG7TadL7cxAoRWzwoXDWE09hCfbyDHp8TBEbEqGQx2inljr3d/r
  24.140 +xA1Kgw4TxJgOXxcV1MQApMEEMM35o3L/rERVsRRKcpQU68wK5TB6mhC0pT/OZRTe
  24.141 +8OLYfArQwrVc8kQKkiaomQENBFgcb/MBCADSCAtS+k5iA0iP700HPpRh6ua66/9v
  24.142 +UQH9NW3WpL8lOw1RbuVTf7focM7NvVmo5C+sHI73zYwBhcf/+z0DoJBTivHOjRyV
  24.143 +vuHJE79XO3DB6Ed0Juu4FI8mt2mPnMI3fAggTR5HK3ghJf96/dhN2s0C32i9O+MQ
  24.144 +G2k5SktTsge/sIu2fmVDJxdtlWfbTOe+QImoYxUCrhomyOf5ramnOmWIIR7oAa8L
  24.145 +xuWTC8nGaiSuvCSgPwo/2dWyMyEGMkokfj3RhkLfGs3IKOXORQicKRYmsHO3p9YM
  24.146 +duXRKDiRQ3H1FedIoaVnxXYbQTtL897PjS6B+BSHquHzJZwrag/KE8+ZABEBAAG0
  24.147 +P3BFcCBUZXN0IERhdmUgKFRlc3QgRG8gTm90IFVzZSkgPHBlcC10ZXN0LWRhdmVA
  24.148 +cGVwLXByb2plY3Qub3JnPokBPwQTAQgAKQUCWBxv8wIbAwUJBzW0AAcLCQgHAwIB
  24.149 +BhUIAgkKCwQWAgMBAh4BAheAAAoJELBJ9Im7W8z29mUIAJQaPFLd3ydRIdBsgg6l
  24.150 +P0ueXH383C4DNPM4cDMfUNwyAqUjYzX09xVJHVMOPRcIfdrZLHZ5t2ro26wqWbHy
  24.151 +nEmIeBBTEf/wLMf4CFKVfbm53zhbOzfFc5TB3hZVCU6pDowGh4POUapzYOkK17QN
  24.152 +Gfm/AjqEuntj0RNO4jISyihqSZH+QEYFv7ZTPZc9VbQ1YvTlXt6As0KW2c1uraOb
  24.153 +uDgmFJlUhED/l2yZfRqwJVjvxXESjSHuLGSijDJlKZBcdsryy06KwzUNRUblbIR+
  24.154 +xgNLnrsZWlb4EXQ9TBth3mShJbIaCMxpOiuavFjtdYBEIxzEpb2QmB7Z9AVaXys9
  24.155 +PC65AQ0EWBxv8wEIAMEWcd7akENhm+qScRlyzJRamB7DJUK79ZtU0DoJuK9FFdjd
  24.156 +FjTvIPkjtPREaaA0GwNjSLkipff9yExk/QtjbQM0oaNBaDOqql9wT3MX9WLZxd1f
  24.157 +eeQ7UW2UZu9zqTuocDimHsCTFDUCWkxrzR3COVN2F+8r3uMqbNrqayUeRpOvn+9C
  24.158 +s6nSGEG70GeaqZnYJyaObwKlWDW5acOnPDicCSKvpRHZY+SJF+n/KjKszmg/EMPk
  24.159 +8j0sYXAZ7/mu8x3XuxfQtb8FeV874cavDGwEhyp9+QVJHNbl5Op7Q/69rSNnfpIq
  24.160 +4B/vL/5yJ/TbVZ9kaeyssKQMgA6nXuyP6pgEDW0AEQEAAYkBJQQYAQgADwUCWBxv
  24.161 +8wIbDAUJBzW0AAAKCRCwSfSJu1vM9ssECAChrPncgPlg7AIZk6TOev9UuqIubbZW
  24.162 +n1GKM67RziylGfisGkE5ZuONPXfbuHz/dS83UzIc7oHwmmPNKhiQFf0MMp3wxaO1
  24.163 +V4w1sPPPkzNlLaorwzZwwGvG5zvYx14o0cZtZVkwQxyJKNDvYLIS+ye7fCySmuY/
  24.164 +Fa5juFmeotuOLt6Ch5QKpMaAUOOSOAay82LP/Ne6nD7AQOIohG0HNvCl9Qfh+AAg
  24.165 +ezWUmTZ+5ZBKcQXukOQ+MplFGRkPMX9bqTZw9Xpg+CccZNFsLfcTrCkuQrk6iyLu
  24.166 +NMxox1FE/ceva2RcWEwM9kdsFQwgtqRhZlmaRIiGydJ9ZPZ/BW+/sd1ymQENBFgc
  24.167 +cBQBCADZpPABxEShbYP4pYn1RNkSTCmOVazU5c418ItfXwSsm/PQ1gisSW1Es4Kw
  24.168 +2ZdAxJVCM1n3D4xM828Cwynf92/M/5yR/i0mAOxEVtdcOIvTngng9+Kf7IQkiP2x
  24.169 +8NXWy/hpdAEoQP/vHfRJMudKRYNSe0qY6qeP4TbO1RUdnL6D2A61gNKYDTBvwsTa
  24.170 +cayYdg3SvQA19xBeYWlMBZG6jOn3U0j4ih7eZfk8e0nGc/zzs+skgyYc+dA/SDAd
  24.171 +h8kkgYf4AJyp+eIEY6HV/xE7hTdFDFLXCVFEav++0Tp88ptnxe4wTkXLYSw8ep1j
  24.172 +OPEGPJzha4ymD39VtGb0I/VYKOpjABEBAAG0P3BFcCBUZXN0IEVyaW4gKFRlc3Qg
  24.173 +RG8gTm90IFVzZSkgPHBlcC10ZXN0LWVyaW5AcGVwLXByb2plY3Qub3JnPokBOQQT
  24.174 +AQgAIwUCWBxwFAIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEK6mn1Cf
  24.175 +jXy64mkIANDZVtKEn6ISslnKQvjUd2oudKVeY+aIjwVvcilnwTmSn+ZPFzSCusjq
  24.176 +4JYW5rurN4evjBV1/6rnKYvVijlC1qwb3bkC5DbV4J03QLBZkdjQz8SvCBgFrBJH
  24.177 +9unpcrgBiLBPoXKQJf/1hsrUt2VwiW/x17eT9awidYnfkrfds/qef5zXIaqY9ejL
  24.178 +pwAY3Jq233jsUdMKugFSeqDpenyKl+5H39h5f/EmI0K/Y4BGoRh028B94qlf323H
  24.179 +zrpuXybIwTvWJ09BVr9wWxDvU+aXrMVB/U+7UsdZm0cUWr6eJoPY/8Pp9wLAM/Nn
  24.180 +qAGKfcfQbsFy3FnGmlqmLvIfrIOgN+e5AQ0EWBxwFAEIAL4eMuG6/UgBY3wSh9LN
  24.181 +n9et3zhX6fNkGFC7YBRX83XxMEtJ2oex+nuvDzgGm8yvGMVX4D/L83Mhkp0BQ3Vy
  24.182 +145n04v37vsa8Xb7wMkdNrYhueauyICWVJaIO0fABNwAh5PXw0J8mZRZeZh6jHXl
  24.183 +9jUc8WYWdszFiFPWp1nswzaFkxmPPizQk58BH96lbb0WH/+jJB3reeeolXqwKfxM
  24.184 +4r2OXrI2lIXCETIDbIz8QuVj3mOlg0lfjiklDVHSnMqthDnGs/IIW/1jjB4TsmyK
  24.185 +S5JqcbKLiasRi6+WwQ9KrPkfC587bvyt7nXf74mKCWS/33kBSFGrOb2xu3nZwNJ6
  24.186 +NC8AEQEAAYkBHwQYAQgACQUCWBxwFAIbDAAKCRCupp9Qn418ushuCADExQ8EvdhN
  24.187 +ueVjvfDplivzF7DEEcUae9zi/2N0f0Ovw+rXMUb+DmMD1O4UJP26ocJ5uwWYumtQ
  24.188 +LjbWDxbzkdsAqBM0yR6eGAyOP3z3E/xHuOne1t8FWLGIVE0oZ9Gj/6qLmCQPw/GO
  24.189 +MXIQPRU4LZrZ2fAmE87yvvV8W4Dw9bOIxDmqgwBoumRG6yiKE0rL7YfdLeBa9FJm
  24.190 +1hJWnpvDLKQjX0+RfQ8kAYJQ3XfJsUq+StnCBlfabFb2G4Y0wJZcsXknXWNVixlC
  24.191 +fQcn2YlZHg3PxgQnW4Fpirq3JXuQQc3+DrMG9LxhQYk7E041hSfZMoKYVuSr9Ux2
  24.192 +wOPKLuggPkXhmQENBFgccFoBCADFipauu1Myw+23yfyHrLwxzneM+i5uchduQ8Be
  24.193 +UmwCQx4ZAzQN+HYf5Ua8o9nSgz4LI04adde9dbEpKDAvp1H6Olv6mO+Pfim6rzR+
  24.194 +iF0akM0Ek6LDyJbSsi7JsZ4GXTqqo7Hb57RmJZaFVn3a5gju4cVuNxr705sMvsTs
  24.195 +uw882DvjkiEtB5kvDCwWHzp8F/19EF2besIu01flrfBlRoVaU5bQRJspA2b39vsK
  24.196 +7t6VqKf4OCsWIfHjW9Met47h3LLHGpE/5M6BfIZVZsWIIozzMc2hoL04l5oJp4hl
  24.197 +ONlKoAj/lvWJUObuUg9uH4/1Lcm4rTXPyKHYoQTJYk457wQrABEBAAG0QXBFcCBU
  24.198 +ZXN0IEZyYW5rIChUZXN0IERvIE5vdCBVc2UpIDxwZXAtdGVzdC1mcmFua0BwZXAt
  24.199 +cHJvamVjdC5vcmc+iQE/BBMBCAApBQJYHHBaAhsDBQkCx+oABwsJCAcDAgEGFQgC
  24.200 +CQoLBBYCAwECHgECF4AACgkQq2lyVpp/xnCiTAgAtxIMvynbGrtPhZrwcgV9aGp2
  24.201 +h6jNasGSThdIPxCVPV/Rtxa5wtnvplA7gzGbW2EXV6Vlfd0AxKKrErkr/b+OAfjh
  24.202 +Yltg8OR5jyH9Ydzy3uq08q48nP/M6ueamcv0X6b4DtygtTzImom2C4bZH/lV+hNe
  24.203 +oXBy0ws2v86I0K96FO9Wr0TfgkDp+wtzUB1jA0IfAJzDN2e4WwFhvtVWyO5qHEht
  24.204 +RFxw8AIDrDCXF7AzWLmRTmlq78/8sDBEMLBBfxtrFvrT0AAluDB9dHa/rhtF5/Hy
  24.205 +FUyRUKLhTSfPFjslBEPAl50qzdNbS1zqN2LB/EPFVFbMFd9P8JZNjVpVyM4oTLkB
  24.206 +DQRYHHBaAQgAryvuu7/9k5wRiSF6gAx/DibsTceZH6CAwtkca04PYUwi2iypCp8R
  24.207 +CSkSQvob7Iw5uzw315G+FbGQUbKuFbCNDoYBacVnS9SgUbd6p0RIe+eAIGbIKDgZ
  24.208 +sLcwvTkLQwVb+V9kS7xYKNvWQ3PEzgvr2qtyJoTNpPZ4Qz5nDhLTYSwwbv6SyqHq
  24.209 +E9Ej2aqlZvq3Umra5L8Xm/dG5PPn3A4+vI/EpNFtu11SN8AJx0W0bYc75ry8vNVg
  24.210 +/jjhfwCadsJ755+my4bkrxT1IVZZYLdS5Kie6hob6P/oCokHc67HtDbzP6j5sOQz
  24.211 +CN0D1ETOa0KCuhhLQvNczsfALbem8+n2xwARAQABiQElBBgBCAAPBQJYHHBaAhsM
  24.212 +BQkCx+oAAAoJEKtpclaaf8ZwBrMH/3cFlXN3G4P2iv2QU7jk1xIhoXHQ9mCkycbm
  24.213 +q3VnBOfNLWXPuw8LgD1xDRN1spRJzhJ0wLWiiM3vl7lsvCwxLa4Id/fQe60ijxxy
  24.214 +X98MdWzp9IsLBocnHPaWjgphpiO8QkoSdfSWLwqe+48YlG8WHnihzMbZckWSxRjF
  24.215 +syjTABxeQhNenvT1vuCn/wt7H0aQM9a+G1KdknOgKnhS4tbXh2dhJ+LvK/RYPQrl
  24.216 +oroUCMqnzE7Jdil+cNXkH/2nlAkq8X27YwikfolgG7/RI4mvlJ3IfcHfVYPp/jhy
  24.217 +8FYwLLgybje9W+8qNufevsKqsALULtRHBDHXyfAUgU0UgfvV6E2ZAQ0EWBxwiwEI
  24.218 +ALMdIVGK7cMwMyndeja1IPht4GSIWHC31R48KxVQrhUonrAg6/5cheyE4D0zI6Sy
  24.219 +2P6/AoPuJcQFx6AhQB0a5q/9aXIZHlvw3pWsqPGjXG7XT1W8tG2rjYF7Rey15ox3
  24.220 +l+1b9FLFN/DMm7/YN37+Ndz4jiD6O0EhmMlVYRCVBcY/eakDHJi/5Yh56GzcnqBk
  24.221 +ibMIR3XoP2Yj4APrLq09DE+4D71mEbd/EE2Fgioj1R2jGBwqlPmgbvbVDQZNj9mW
  24.222 +WpZNLMSVdMThUAwn832zCi71nSBVtNdAT/t+2uBJNjhZyoP2jj5SdtN0+xKK8g57
  24.223 +fvBq8eb921Qqb0lA1JNNGOcAEQEAAbRJcEVwIFRlc3QgR2FicmllbGxlIChUZXN0
  24.224 +IERvIE5vdCBVc2UpIDxwZXAtdGVzdC1nYWJyaWVsbGVAcGVwLXByb2plY3Qub3Jn
  24.225 +PokBVgQTAQgAQAIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAFiEEkGybg0mV
  24.226 +ToLFYjw8jFQb1OIDWGwFAlvpOBwFCRaYypEACgkQjFQb1OIDWGwMLQf+J2akCkFX
  24.227 +0+5ijTsF6Sahis+1Gr4K6Pqmrzpitrb3uQkKGW9AqmQwqOFWsvuUKN1kvVFnGrgL
  24.228 +AIEsl7r9Dv3m0mEwLVW4xgEtrEonqoJxwvuWPVitCOQHux3b/Dcv4lrFzEn5aIf9
  24.229 +DJu1Dhc+sqfbXtB+TEUV7vIfNrTGB8NPRZ5gbGqrwNdP5SEdL+dpw4SnpSjXLsCe
  24.230 +FKB5E49Kjuw/w7SxE7XJMopHuDflyKNaJIXrXieGf+STMaVmxzeGK979L99I2Ztu
  24.231 +kHOO+u5ZWHnLD+8Y/Iq1h9d8HHlgVKcOZGsdAziMDbwDsJchxj9cnRdy3XMkv2qL
  24.232 +2qq19s9Wx3gdOrkBDQRYHHCLAQgA1EV5Qc7yzkFSZcRMgVGpivFK7CxpvQxOQ1wU
  24.233 +q+ZxH+SY3P3atHrgOgTKe0fnJOkau47b8P0vMfXRBF1fHSQS6hwzYPxlyumFC4KW
  24.234 +kx16mIZHZoMyl9E/O61jMz/xKRl5DpiQWGHzwvod6hADXhDWzllZR0mq2YBOQW9R
  24.235 +htJGEE98gmNoMynE82Ktit+o39nqBILw4Dh0YXgvdkuW9m8bX4vJZcSHs9rNaSZL
  24.236 +x2ANk0NGcNSbM/yU3z98I1wnQREbD0an10e9olcEBRitdkfzdrdm070PlpThtcsA
  24.237 +VAPpUYR9i+DESHNBdIakZmhPC2C1dGh8x47YgHj95ffpWfk4gwARAQABiQE8BBgB
  24.238 +CAAmAhsMFiEEkGybg0mVToLFYjw8jFQb1OIDWGwFAlvpOCwFCRaYyqEACgkQjFQb
  24.239 +1OIDWGwQBgf/WldZURawx4btqWe5ENLDWB7RJopDPPx51GRQmN4iP66T0NpZTI28
  24.240 +P4jWeXMyB1PireKxqqJGHCmOcZt/248m5kMLgvK/MVd/lrLB88nvotvlANQataob
  24.241 +alzUSl8Bydi7Fqg0+xIduCWMuqDTJC7+EOouTBnkXOzx6dyhtPhoWruL5VDd4LRk
  24.242 +xRv5NbiYsCT1LL+b4yUFJtI8HkBKYbqPkLINYlkkNyIKRZ0Pdl5HgBGf20g4EnLX
  24.243 +7hUYxWEs3qP3PsQHzwjg5NcYoU7KEIV4Ry+zjn2+OJJLjOcWoVHSKcO8vUC4342E
  24.244 +z2K9EV9hsqxglctCT2DlPpka7ulk5HWJf5kBDQRVeD72AQgA0e5GhS7CxQ7hhNdb
  24.245 +t6tiunk7KQJHM1NWoT50l2lRjiGwkBri+jIgxE+L1wGP8taYnKifDriHtpNEvHg0
  24.246 +SGCBxfGq4YE5GUJ8ugn8u54XljZ8UmQSKCv/GamvXWzQVsB6dpeyzqjN4UvGtDtZ
  24.247 +kEK6zJVeeap11iUBWiNz/55WhlH3vuQ7g7Q6JvMSYnBPGp+Z4W7MisjcZWFXj1bE
  24.248 +FRYixzFaDWensn8m/50wXQHUNCi2TNLwwvHX/1U3r8rX/z4Lp84qg+ux7g8fFMcn
  24.249 +obeURCK3ARMq4LZ705FY2SdjKW13GNpGpt+jh/E+CaAZMZao1OlIoqlfpNOEMwL5
  24.250 +qdv2pwARAQABtENwRXAgVGVzdCBKb2huICh0ZXN0IGtleSwgZG9uJ3QgdXNlKSA8
  24.251 +cGVwLnRlc3Quam9obkBwZXAtcHJvamVjdC5vcmc+iQE4BBMBAgAiBQJVeD72AhsD
  24.252 +BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRATXNbRcNz1da0LCACBsZjB4wEK
  24.253 +rGQewkAHRHVsTPmJBmTwDqjGGa1Wn/sIiJDD9uQfSWkmEXHGGyPpPlYNfZeb6lb/
  24.254 +4sYAy57WViRbdy2pCpE2N0fIIYSiJpVVaII+gEoaNK1KBy6Qi7qNLfjfgxk4wTot
  24.255 +bbvdFPS96aD7IGDoo+qcNtujOs17L7JOIVLpY6vWcrCm4xhKKmoTi3+6e4I67QnH
  24.256 +jkH6p1yjRPUJaULcP6Z8E2ve4FUeJew2ilBF8wEqG4xMsHwqDB/UmqFS+TPxbCJD
  24.257 +EmrIOh/ieFPGHcROcdgUW00HvvdP0ZVYOWzQivZzCgTAa9CnniZ/SWUcpMCjoFeb
  24.258 +2ZdJUOQRChImuQENBFV4PvYBCADBLw6PfOob/aZOGCiy0YWVcqdyog0Nspo3ZfL/
  24.259 +5Idn97Nq6DYReaNqU36udaEwiHsdFosq4u6P9VdtXt8GEteLkcxfOmuXL5jnUf8N
  24.260 +fjblu4aFvUVgRGguzuDf07VOwAEJmr/JgAiQR8HaBPfASpiTQBt0jof5EnYeR2ay
  24.261 ++WK8eLV+3ZCTlyNiapdCEuEd+3ZgF+SvvTKiBQyX9CO94ogRq9L+pmzghKJwc5xf
  24.262 ++h/dOQotrj2d/Ax4sTdnMk6GYOwpE3wuyvMZhxb9ZXEc5UzMjQtMTpYq2Dz5YZxr
  24.263 +Jcoskyah1cqx/2e/PMesFfYnz5w2XxpkZAtlfB0wUUIXSLkRABEBAAGJAR8EGAEC
  24.264 +AAkFAlV4PvYCGwwACgkQE1zW0XDc9XVCrwf+Op74yjU7TyV4nQK5Dz/K2Oe5BFVo
  24.265 +PLKZKgViHldwBjM4falX0Ub+D35fSIB2jr15KCoqfQ+M74KQeeuoCIhNwd2OLxM0
  24.266 +6IgcalaOS+YM5mxuidXEHR8+q5ikhz3+M6zUGwsWhlyCeve5pXyiIiAa1eu7B915
  24.267 +tpehAqfD4kBiJixWgSNkm7i0h0s9ZwvddJZ/AIUmAGJcWAXWrXqNyGcAGUkImwhf
  24.268 +8Qob5w3A42WvRlqN4jJUjwKCl2nG63Xp4xf1/csqHk7UzU7jQxq/UprO9sFPkgGB
  24.269 +Kyw3IpNaUYTQ5i1xI0Au3gU/VhXppHzlY5gyo6J2/cgM+pJ8QuZEROQoVw==
  24.270 +=o4Ql
  24.271 +-----END PGP ARMORED FILE-----