ENGINE-420: tests still need memory cleanup, but we seem to be in good shape with private key trust on green channels (and NON-trust on others) ENGINE-420
authorKrista Bennett <krista@pep-project.org>
Mon, 16 Apr 2018 11:38:00 +0200
branchENGINE-420
changeset 26008fc17cbaa30f
parent 2599 b02405e4e373
child 2601 9c12675c68e1
ENGINE-420: tests still need memory cleanup, but we seem to be in good shape with private key trust on green channels (and NON-trust on others)
src/message_api.c
test/decrypt_attach_private_key_test.cc
test/test_mails/priv_key_attach.eml
     1.1 --- a/src/message_api.c	Fri Apr 13 18:33:38 2018 +0200
     1.2 +++ b/src/message_api.c	Mon Apr 16 11:38:00 2018 +0200
     1.3 @@ -2690,9 +2690,9 @@
     1.4          // the private identity list should NOT be subject to myself() or
     1.5          // update_identity() at this point.
     1.6          // If the receiving app wants them to be in the trust DB, it
     1.7 -        // should call myself() on them upon return.
     1.8 +        // should call set_own_key() on them upon return.
     1.9          // We do, however, prepare these so the app can use them
    1.10 -        // directly in a myself() call by putting the own_id on it.
    1.11 +        // directly in a set_own_key() call by putting the own_id on it.
    1.12          char* own_id = NULL;
    1.13          status = get_default_own_userid(session, &own_id);
    1.14          
    1.15 @@ -3097,7 +3097,24 @@
    1.16                                                  free_message(inner_message);
    1.17                                                  goto pep_error;
    1.18                                              }
    1.19 -                                                    
    1.20 +
    1.21 +                                            // check for private key in decrypted message attachment while importing
    1.22 +                                            // N.B. Apparently, we always import private keys into the keyring; however,
    1.23 +                                            // we do NOT always allow those to be used for encryption. THAT is controlled
    1.24 +                                            // by setting it as an own identity associated with the key in the DB.
    1.25 +                                            
    1.26 +                                            // If we have a message 2.0 message, we are ONLY going to be ok with keys
    1.27 +                                            // we imported from THIS part of the message.
    1.28 +                                            imported_private_key_address = false;
    1.29 +                                            free(private_il);
    1.30 +                                            private_il = NULL;
    1.31 +                                            status = import_priv_keys_from_decrypted_msg(session, src, inner_message,
    1.32 +                                                                                         &imported_keys,
    1.33 +                                                                                         &imported_private_key_address,
    1.34 +                                                                                         private_il);
    1.35 +                                            if (status != PEP_STATUS_OK)
    1.36 +                                                goto pep_error;            
    1.37 +
    1.38                                              // THIS is our message
    1.39                                              // Now, let's make sure we've copied in 
    1.40                                              // any information sent in by the app if
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/decrypt_attach_private_key_test.cc	Mon Apr 16 11:38:00 2018 +0200
     2.3 @@ -0,0 +1,168 @@
     2.4 +// This file is under GNU General Public License 3.0
     2.5 +// see LICENSE.txt
     2.6 +
     2.7 +#include <stdlib.h>
     2.8 +#include <string.h>
     2.9 +#include "platform.h"
    2.10 +#include <iostream>
    2.11 +#include <fstream>
    2.12 +#include <assert.h>
    2.13 +#include "mime.h"
    2.14 +#include "message_api.h"
    2.15 +#include "keymanagement.h"
    2.16 +#include "test_util.h"
    2.17 +
    2.18 +using namespace std;
    2.19 +
    2.20 +int main() {
    2.21 +    cout << "\n*** decrypt_attach_private_key_test ***\n\n";
    2.22 +
    2.23 +    PEP_SESSION session;
    2.24 +    
    2.25 +    cout << "calling init()\n";
    2.26 +    PEP_STATUS status1 = init(&session);
    2.27 +    assert(status1 == PEP_STATUS_OK);
    2.28 +    assert(session);
    2.29 +    cout << "init() completed.\n";
    2.30 +
    2.31 +    const char* own_uid = PEP_OWN_USERID;
    2.32 +
    2.33 +    cout << "Importing keys..." << endl;
    2.34 +    
    2.35 +    string input_key;
    2.36 +    const char* main_addr = "priv-key-import-test-main@darthmama.cool";
    2.37 +    pEp_identity* main_me = NULL;
    2.38 +    const char* fpr_main_me = "13A9F97964A2B52520CAA40E51BCA783C065A213";    
    2.39 +    pEp_identity* same_addr_same_uid = NULL;
    2.40 +    const char* fpr_same_addr_same_uid = "8AB616A3BD51DEF714B5E688EFFB540C3276D2E5";
    2.41 +        
    2.42 +    PEP_STATUS status = PEP_STATUS_OK;
    2.43 +
    2.44 +    // key for main own user
    2.45 +    // 
    2.46 +    // 13A9F97964A2B52520CAA40E51BCA783C065A213    
    2.47 +    input_key = slurp("test_keys/pub/priv-key-import-test-main_0-0xC065A213_pub.asc");
    2.48 +    status = import_key(session, input_key.c_str(), input_key.length(), NULL);
    2.49 +    assert(status == PEP_STATUS_OK);
    2.50 +
    2.51 +    input_key = slurp("test_keys/priv/priv-key-import-test-main_0-0xC065A213_priv.asc");
    2.52 +    status = import_key(session, input_key.c_str(), input_key.length(), NULL);
    2.53 +    assert(status == PEP_STATUS_OK);
    2.54 +
    2.55 +    // ensure there's no private key
    2.56 +    bool has_priv = false;
    2.57 +    status = contains_priv_key(session, fpr_same_addr_same_uid, &has_priv);
    2.58 +    if (status == PEP_STATUS_OK && has_priv) {
    2.59 +        cout << "SORRY, have to delete keys here to run test correctly..." << endl;
    2.60 +        status = delete_keypair(session, fpr_same_addr_same_uid);
    2.61 +        if (status == PEP_STATUS_OK)
    2.62 +            cout << "Successfully deleted keypair for " << fpr_same_addr_same_uid << " - will now import the public key only" << endl;
    2.63 +    }
    2.64 +        
    2.65 +    // key with same address and user_id
    2.66 +    // 8AB616A3BD51DEF714B5E688EFFB540C3276D2E5
    2.67 +    input_key = slurp("test_keys/pub/priv-key-import-test-main_0-0x3276D2E5_pub.asc");
    2.68 +    status = import_key(session, input_key.c_str(), input_key.length(), NULL);
    2.69 +    assert(status == PEP_STATUS_OK);
    2.70 +
    2.71 +    
    2.72 +    cout << "Setting up own identity with default key " << fpr_main_me << endl;
    2.73 +    // Own identity with default key etc
    2.74 +    main_me = new_identity(main_addr, fpr_main_me, own_uid, "PrivateKey Import Test");
    2.75 +    status = set_own_key(session, main_me, fpr_main_me);
    2.76 +    assert(status == PEP_STATUS_OK);
    2.77 +
    2.78 +    assert(strcmp(main_me->fpr, fpr_main_me) == 0);
    2.79 +    cout << "Done!" << endl << endl;
    2.80 +    
    2.81 +    cout << "Setting up sender identities and resetting key trust." << endl;
    2.82 +    cout << "#1: same address, same user_id - address: " << main_addr << ", user_id: " << own_uid << ", fpr: " << fpr_same_addr_same_uid << endl;  
    2.83 +    same_addr_same_uid = new_identity(main_addr, fpr_same_addr_same_uid, own_uid, "PrivateKey Import Test");
    2.84 +    assert(status == PEP_STATUS_OK || status == PEP_CANNOT_FIND_IDENTITY);
    2.85 +    assert((same_addr_same_uid->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed);
    2.86 +
    2.87 +    status = key_reset_trust(session, same_addr_same_uid);
    2.88 +    
    2.89 +    cout << "Done!" << endl << endl;
    2.90 +
    2.91 +    cout << "Reading in message..." << endl;
    2.92 +    
    2.93 +    string encoded_text = slurp("test_mails/priv_key_attach.eml");
    2.94 +
    2.95 +    cout << "Starting tests..." << endl;
    2.96 +    // Case 1:
    2.97 +    // Same address, same user_id, untrusted
    2.98 +    cout << "Case 1: Same address, same user_id, untrusted" << endl;
    2.99 +    char* decrypted_text = NULL;
   2.100 +    stringlist_t* keylist_used = NULL;
   2.101 +    PEP_rating rating;
   2.102 +    PEP_decrypt_flags_t flags;
   2.103 +    
   2.104 +    status = get_trust(session, same_addr_same_uid);
   2.105 +    cout << tl_ct_string(same_addr_same_uid->comm_type) << endl;
   2.106 +    
   2.107 +    assert((same_addr_same_uid->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed);
   2.108 +    
   2.109 +    status = MIME_decrypt_message(session, encoded_text.c_str(), 
   2.110 +                                  encoded_text.size(), &decrypted_text, 
   2.111 +                                  &keylist_used, &rating, &flags);
   2.112 +
   2.113 +    status = get_trust(session, same_addr_same_uid);
   2.114 +    assert(same_addr_same_uid->comm_type == PEP_ct_pEp_unconfirmed);
   2.115 +
   2.116 +    cout << "Case 1 Status: " << tl_status_string(status) << endl; 
   2.117 +    cout << "Private key is not trusted for " << same_addr_same_uid->fpr << ", as desired, as the public key was not trusted." << endl;
   2.118 +    cout << "PASS!" << endl;
   2.119 +
   2.120 +    // Case 2:
   2.121 +    cout << decrypted_text << endl;
   2.122 +    // Same address, same_user_id, trusted
   2.123 +    cout << "Case 2: Same address, same user_id, trusted" << endl;
   2.124 +    
   2.125 +    // remove private key
   2.126 +    cout << "SORRY, have to delete keys here to continue to run test..." << endl;
   2.127 +    status = delete_keypair(session, fpr_same_addr_same_uid);
   2.128 +    if (status == PEP_STATUS_OK)
   2.129 +        cout << "Successfully deleted keypair for " << fpr_same_addr_same_uid << " - will now import the public key only" << endl;
   2.130 +        
   2.131 +    // key with same address and user_id
   2.132 +    // 8AB616A3BD51DEF714B5E688EFFB540C3276D2E5
   2.133 +    status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   2.134 +    assert(status == PEP_STATUS_OK);
   2.135 +
   2.136 +    has_priv = false;
   2.137 +    status = contains_priv_key(session, fpr_same_addr_same_uid, &has_priv);
   2.138 +    assert(has_priv == false);
   2.139 +    cout << "(Double-checking - Private key successfully deleted.)" << endl;
   2.140 +    
   2.141 +    status = trust_personal_key(session, same_addr_same_uid);
   2.142 +    assert(status == PEP_STATUS_OK);
   2.143 +    free(decrypted_text);
   2.144 +    decrypted_text = NULL;
   2.145 +
   2.146 +    status = get_trust(session, same_addr_same_uid);
   2.147 +    cout << tl_ct_string(same_addr_same_uid->comm_type) << endl;
   2.148 +    
   2.149 +    assert(same_addr_same_uid->comm_type == PEP_ct_pEp);
   2.150 +    
   2.151 +    status = MIME_decrypt_message(session, encoded_text.c_str(), 
   2.152 +                                  encoded_text.size(), &decrypted_text, 
   2.153 +                                  &keylist_used, &rating, &flags);
   2.154 +    
   2.155 +    cout << "Case 2 Status: " << tl_status_string(status) << endl;
   2.156 +    assert(status == PEP_STATUS_OK);
   2.157 +
   2.158 +    cout << decrypted_text << endl;
   2.159 +    
   2.160 +    has_priv = false;
   2.161 +    status = contains_priv_key(session, fpr_same_addr_same_uid, &has_priv);
   2.162 +    assert(has_priv == true);
   2.163 +    cout << "Private key was also imported." << endl;
   2.164 +    
   2.165 +    cout << "PASS!" << endl;
   2.166 +    status = key_reset_trust(session, main_me);      
   2.167 +    status = key_reset_trust(session, same_addr_same_uid);      
   2.168 +    release(session);
   2.169 +    
   2.170 +    return 0;
   2.171 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/test_mails/priv_key_attach.eml	Mon Apr 16 11:38:00 2018 +0200
     3.3 @@ -0,0 +1,184 @@
     3.4 +Message-ID: <pEp.P74JAT.0V8ST1NR4QM24.AF3319ED-96D4-45AA-94C6-91640DAAF536@darthmama.cool>
     3.5 +From: PrivateKey Import Test <priv-key-import-test-main@darthmama.cool>
     3.6 +To: PrivateKey Import Test <priv-key-import-test-main@darthmama.cool>
     3.7 +Subject: =?utf-8?Q?p=E2=89=A1p?=
     3.8 +X-pEp-Version: 2.0
     3.9 +MIME-Version: 1.0
    3.10 +Content-Type: multipart/encrypted; boundary="1bf5eb907b76716d2b9eab6525e9c2ea"; 
    3.11 + protocol="application/pgp-encrypted"
    3.12 +
    3.13 +--1bf5eb907b76716d2b9eab6525e9c2ea
    3.14 +Content-Type: application/pgp-encrypted
    3.15 +
    3.16 +Version: 1
    3.17 +--1bf5eb907b76716d2b9eab6525e9c2ea
    3.18 +Content-Type: application/octet-stream
    3.19 +Content-Transfer-Encoding: 7bit
    3.20 +Content-Disposition: inline; filename="msg.asc"
    3.21 +
    3.22 +-----BEGIN PGP MESSAGE-----
    3.23 +
    3.24 +hQEMA3tc/VFAGHIuAQgArxj6Z3+qUjvbvCRds8G0MRD4kbN6qKQeTomC4ACSbp/R
    3.25 +skwIJwBzVcmOFlmFjD2Utpq9k0oYnjjAAKB2LFJtAf0tdugzsq3PNXRHwJkIhwaE
    3.26 ++l6irh/GlbF6emEkJcqEuqmqyyIAaDB4Th/YZNMdhbkTrUaFsJJUVNJ4wgI5xgMv
    3.27 +wG8eKut2mQM3TMMXC0GcAl1hO24jGoLccTPhjLZsClQ0wPBt/Zo6DZ/U2a1SAnE9
    3.28 ++5rzL+f8DRc71d4Q8ahgPjv6YFquwJP5SbRWng7Y9HoERnFSULiG1BqxhZvWOHBC
    3.29 +jsUIXuuVUPdQ8Dkf2NMovXKw8Jar39T/6ZGOPDI2FoUBDAOK/P82gcSJMgEH/318
    3.30 +rWzjFq3tVqHkjVKAt9XLQA28CF3hq9FamB4D3gTg85t5Z5aRvl9tCOVl7sCfzQov
    3.31 +mSAHad/2Jm8LV2W3i+y3jznfNo+7gIfW0J1KHXBDsdhXZyU52Ylg8qDTrUstSls1
    3.32 +sBV08UxrbmOlbdRHV61CaZ31bJleBPru4dtenOJQGZIuxjAFEbb2EwNO38kZNQ3y
    3.33 +KEvK84jKPAIx2iPkfl+ruS461zb+iQpIsaGS1vKp19yZwwBMal2/v7/JcQUlt27H
    3.34 +/7UmseANMjCB5JfILBIRlnVXcaJtMpaJ4PnYt1OieectT8vEKYyOrAK7iYQ7vFJo
    3.35 +CO3SBSRP4UKmSM4HAbHS7AHljGy1AN5I75bJ5BWciL9HsmPRJYsQpHHLt7IA5W6l
    3.36 +D53RPD2B7JkzRV3B1wWPiXfaNHiYeBNPIzOMNiGmZdgBZ9pJRUGzthXHHIQBBOxX
    3.37 +oxsQI9biaYiCQL3cvlVMvPG7eKt82zzbZsvemhPF3xwWpJ7tlLMrdcJzh9HBGeJ+
    3.38 +7N6fh9jt8XbAF29ruO4lSoIu8triOOsloOEb2e+pMrvOMmSP12uJCY/yrFFhCuhi
    3.39 +z2yyRDqAfB7J8uKYbCmY41He+sF3IcDJGyfDdaVK5fv4bBUMcmYdzVUfZfBaNI0v
    3.40 +50wOhkOvg50mw5egkHD5ppX4PVk4Bx27OMU23XbLQM6c7VbBN2HH/R2+KN3FuHVE
    3.41 +m56rartfyxyr2dIPixwAiAV9TiJIx997g31KIgWflgb0PJMYZsik3PrCbJAZBr4q
    3.42 +PG80mwKvdiFA1xH2/JpGCHhorvvQoxuGOFvhGuTeZ5NyrKR28IWEk+TvEu5jmxxj
    3.43 +yCD7TA7ldjx2G11z7oGnJ89ErVf2ClQ835ZHyr2z3Hm0gluqppM09Sh+jvqtYenO
    3.44 +0FihhiNKGxG0CWReO8LaWq4nXAmxoBJklCqUlisxxTeJeTigqhMnv5V0myi4iFKR
    3.45 +Gr4gUSLu+XhwugCU+fuWzpiaDIN/Q747SZdZmNOAA7puxrO49q/7v3iKYUquGufk
    3.46 +Dz4TSAzVIJ/VEIojV7IIMv6GzXfqAfz6OkJVZNo+L9IWlYwr2xCjClEO7PWXswGl
    3.47 +MFtqBWAV86lvSDAvwIqgr8reDGX6vMjbhZQC3G8Oy0+k/kNmHweIskK0R8LeZiZh
    3.48 +0I7gjRDGEHDTDZuFafxO2w80HEgfxbiI/7cIRKV3dEMfrlwmgPTOl9C1UiUal1aC
    3.49 +pMnTUYWC7Gg+eI/TCPxXwQnzE1JTlVsqWepMlJMevUZvSwFcNqjsGxWzYRqDRq2I
    3.50 +ItkDDkqFMccVBOeF9Jrp/M3vZfQ4PyWPmAF/YqOi3FsaihFiZ4TnShyH2XIEkAK2
    3.51 +/8GpdSdPBOOjmBG+mCAvo1IEzKRizQ3biaVkR1wh7H/2JuIcx4BL+A4xkFnFfFe2
    3.52 +OsoS6Ru+7dTqTypjPPUMrWI6d7lKHvD55fJT5S5jDy7GUK4B8o2ae8I9Nz11vIt+
    3.53 +TyFf+WuO7VPkeBWaVqp9why5bisLhuRpb/f7uItVEChsqLj6eV6CTr3nht804nRk
    3.54 +vHKQ8KQbb+2mAarhzXaG97eKeI4Lj+XEGVJrIrixvjg4qEB0oDguajuUZc1DIFXi
    3.55 +A+JcOjzB1Nix5X6S4I+MV7rstUwJy9hKucY3liWckHeSAwLPcPQipKa38F7eCYuH
    3.56 +7ajbQJvXEeT26QEtWBqX+V4DlXEvVMKqXtRCptMsNTT17Fl1QK0ZCy5Np9CsNJ+H
    3.57 +Rr2afAc4ptfSrGoICpHd5GkuF8PyFboKiR8XkUm7o6eZtaxPbszYwiE0rmRR/XY+
    3.58 +WdPHXfaSzpNYXximYgzDKjteEw4O7uy/BDLqcvfLe8nuyn4xSpvbPdX0cBCOb5Yo
    3.59 +yhYfffeumJvn/L/rwT6zg51O58l9NVLj7bvSBVbCi3JQMZzDPUfOIqsTuXhV2uCM
    3.60 +ZbryRPDTL7uPkPtetz6Qu8+xtRAgRbip/aS1H1Kntjklu3P61s80ObB7yJ1WlcXG
    3.61 +r7biS+xjLe9ShvA4BcedQn1ocPjYlep4CulLX1oVKfW1vJaE/CEceQkXqgJkUvoM
    3.62 +Z3GbHu8q+cpOM2Tx9PO15oQD+yaaqNewoNBLrcjkbDJEAYiFay0ol/XgEhF3P+i4
    3.63 +Jq+EpB8bbAYbPpEKE4rFTVHqn42s1lkjekW1/cG7H/bGw/ynWiQmK5AMLmSdssht
    3.64 +kEbJgcj5hqk4bdiJBtHxbvPvMBFQ6z5/QMkHgoaRAnyIoyAk3w5y/b9GOEFZRig7
    3.65 +uh763Vau50F/oUPEwyhzYUXzqTnDk61R/inyXNzx1IU1pnijbL2svmcUViUhlF4C
    3.66 +uuzRLMkrqgSsDLXZvAx0yL4yJmutpGOiipIhexQ3287idNTHeolsMxLVaSXwRF7s
    3.67 +O+bi5JYUdaEoTHNQGW8HgZHuMyqiKbX5dgXtSBD0mlqRvRZWWgQXZEWepv4oxcZ/
    3.68 +qTW2oelDPd3TaBIG749HoQODUCGsi/ic+Q6G0KRBiG/ryyt0u2FGdlTVo2HHrSbZ
    3.69 +C4tlNRn2eY1gR//YOdg+XjvkXBRcHd/Ma1JoAIVegQZeCOpKTGFGEMKzNq/18rv+
    3.70 +VcFNnxj+qzCZMlJrza8K6PXkvW5iXj5eWZBhemO/1zOe/57EbTAgS1Rb4ip8D4Xo
    3.71 +ddRp+Js7jDx/pqHyQxdORVbzplruihACiw2Eick+r2QJixG2MUTgK8vNnXyeu5al
    3.72 +96Gn/G4xyOS5dOCf3omzvM/dhGwHgDTs/Ikdza8W6zXqAu1Uamfqon/DwlOGBSRC
    3.73 +6abrGmcp2nqT59uKB4N+KEBnjXB06wForP3UVRWAgcmpxZ9XnN6pcOlGrkHfF/Cw
    3.74 +FlkwiTZt2BNKaYrTTgnnmpJU82dHU7Te6X67PEGDXWKj1Puq1ZhADJTWwty9Y2ec
    3.75 +u8a/trHjAtyjetSMjQAtNqsh/QbGgh5AZzzHmCBsCPRqx96hHVn9U1ooirfLX4IO
    3.76 +xSDv8jGPB8LXPW2qDJKedg6SXJtbn0OayJ4pwHZT9iZ4QDoUdV4tkhhqrntJEFBt
    3.77 +EeWcEE4ltsyQKUY55sb38onHFUDM2+wJaNEmRsxNXXmQ5CccO9gR+fwNOAkSEwQ9
    3.78 +VJ9XkU9H1s29bapYASTfNxynMKfoZVwFpOthdzCL6IUX0uRQguGTT04BcJQSkyua
    3.79 +FVXHoH8Mtf4V6bP1VCIuag1Vwpdz6KaEVyAuzRgjDgLf5ohrcfrBbI7SZomR70d7
    3.80 +i2mNQSXlyXYshalK9TvAxZIRpmdCm8Efv/8+MrYsoieyIvJS+4leZI3TgSrIVjLC
    3.81 +2Wa1+1E3J/LMb53ut/rKGUkGGvB2Wn1ZlCkf/X9+ulG6d4g8geexnSKuNHt3OCfF
    3.82 +yfr6dMc6EIqUVGzlvFb3Cru7faYGBEwQDdX5yTAKV1X7RGm+vPXEnRIOIGtnCiN1
    3.83 +jIFtuU1SzDMXZqtVxxhByChrM70JNQwvKiFsma3kWWxBl9+ujrVaPO1lDsV3ZIrF
    3.84 +RYM0t+a4O+FKG4P/DIEKcwjXmxmw1UHNZGSfcvSV8rbLNijh5D14Xb/FlN/Uf3mm
    3.85 +tiYb9cXK7zXmPunwpVBXeHivUG9t0Ndi9L5UQvAVrFHNyxQ+UUEdIpPyd/jN7z6H
    3.86 +2ViqHIqlgIJniHoedxlOXh6CMSYGZQez84DNqX6sk4m+guhHwCp5bZXvXByEfZHH
    3.87 +R0ZGm2K8Wvcqq7k7n7l9aW2WWK3P/s8IMXyBwa3rcdZ+hvCRePBqWjFRXHHsMn+N
    3.88 +i4kWNWxWvH0luG1xG9J/DKmOYbIhI7iPZ52+hJ6MiFiSCNipZ5sl8u//r6zoTHl9
    3.89 +EX5pAc4hpz2skQxWnN8hQEOtNbxF/gZvg9vyKkvOsEtwspuz017tTRLvWd+mhhFA
    3.90 +FTroilfjIR9TG9REagP736fyMCCcdI+ZMWafIZTdUw1RmfxIYUvVl16D2OaasBN4
    3.91 +zWTx4yNjb9A3lHc7JdzF1IILC7FKGLJrXyA/FkGz2a/5Z8jUof8+fS3GFCqqgDyi
    3.92 +cz5ZvOAn0xPJ2sPa13d8NLlZ5CJFRjEHFkSihQ7A5TD6g4sWAAw2a4+4s5l4zRk6
    3.93 +W0nMBbSbQxHvosGJDjolhSM34bIYLGGmq1P5RbPfNeyXhRfSMGFqrhdnZp/WWPln
    3.94 +ZmA83KuRubeuxsNotJ6ZWz7JfBhkZUuTkt7sPlzwSL59a5uDBveUQqwWyvR6tpft
    3.95 +4WDA8/dZjnEuwkE76uquEzxCUSb7PSbOELrf4a7djpnmE0WK+yhTviWIpL/zer7N
    3.96 +OXhbRoX6G05KApGZMQeSZcAYOhuDTKSSv5bFCoIwUfq0j+Pj4Loely6SO38bLFWk
    3.97 +VgXOFEMizGLKYLLzn9ZPpKnlZTGCxs4c+j2SOm6ByJuSeJxw8bjlCb+BwOCx6cSc
    3.98 +JP2iUfVbbwK2hHZNQ9/e7YrlXfV0m4EanL3d8/nehcd6DXbmXGuhvAEQjgaqBwLV
    3.99 +PAMxH5t5ZLIQFO9emYJ5c0iL/reiQhA7lEU1SbruHUWa2wHc4WCQzmjdbU9vmWa4
   3.100 +5mwSVN25ZV8/2SO4uc4AMo2uCx/vgOTzBlCP7ePqr9ebOs56LbIwuJghi/FD2s7+
   3.101 +5/ljPL5HDlhVC4qmIuJeKG5htGqDcqtd9rEa9+i2Pln0I9CFivR3vAR1GwtTTPqB
   3.102 +1ieqlJnLTVZevnDas8TSP0GDi/VFD2CfC8UVbevbMnqq5wlB0EO9UWFcqN6XueIa
   3.103 +byEd3BxF38BaDpQQ2XOYb3eX6ZP90fLtqMODivS9DhMsErq31Pg5EAe+CNm3nEPN
   3.104 +avoCMrxqMkJAuC+OGw+5yh1+2oXzsGr+he+DddatSlUzRp7nAf36PePHUPNqiAqp
   3.105 +KAbEkjyhP9nPwbeYqcF+oiW4p9WLODxD54IfMW+7KHbZUJ2ZnuKk//VFlgtbyorc
   3.106 +JiGET0iCqXT44nP2N3UmnWj3hU0NQld8BECCZQjCJsiGX6XI5bUsekEUgLRx2ryV
   3.107 +DDnmUaHem3xo2TT6tgcIAjHzGVjvTPaiGF717xMkG86JtKP83idphcFZAFVILK8j
   3.108 +7GCbCI2ZVzQD1iBK87RAj7j/UZElMcGu3YRyQjmVSFi4s56qO5GRPGiIcqVTuwuo
   3.109 +Ar8RTBq3ndwQfmPU5wg+Sp6EiayZocfYc4Uxhb9bGUMIyAsOUXDwi5oGw7da5Q5U
   3.110 +iDo/YmChZZPRrcd+TjoVqUoBUS3twWXAlVnsLV16BWG+Zsdh7CyshRO9T98VXQrP
   3.111 +Zw9/ZNWuRkqdHajs/TAMhsy7ewNOvDb9fB9Fqnp1Ea+kb/uLV8k6kPQcjfeSqruN
   3.112 +5ZZfGK/EnG3mu3009Hqb+ev6VdSzAe7mgOsb1N0SGsYqBNeg3r0i+njcIwhXBJ+J
   3.113 +IPOtN0uq6Cb1Nb+NRVvH3ACbBytNe3o8nYcjkL7dwf8Tfw/AtOZQb+WpUJW6hgDH
   3.114 +vd/Fr6b3JYGslQ9Apw+1oKWtE3+lAfzgmitVATkpxFxr7LFXWVWwycbiH2WbD66i
   3.115 +JSwTdAVGcB1eWNj9JkGyflscato9YURTagBMAxSceaRd/FUKhOkVPGrIt+6oWaYN
   3.116 +tyA6+wj9ytDVy2nQDdLr66W95b/F/FmxCnZ+aCtTEzUB4yahreHH9bKmXAjOKVl0
   3.117 +kFehDOXwUDo50N3CdOZ3IwPEocNkmwRab3IaK88SZDhz8ZuOMTpkiD+R2Xtv3ZLI
   3.118 +fNUxkekhoEjaFDDu38xmzjqaZau3Iu4SVygW8owhkFtY1DndKqg5Azfw1A07apUF
   3.119 +Uche+kPeWHlkIAHdfO7hoy6wg4zTHxW/e2lzHIwAEKNVg311ST6ojCFe99SAZ8Tm
   3.120 +tdFLNa8SGwmqtBfjY+A02toQrVF1Ypl8GNVZUKt4ogbraeZh8KA3DSkY3B67TotT
   3.121 +1ETHDwXrAXsYMyxXklEBZUtXYVMw9h+B6TjZbYvzgiYxIxhINAH4/8zbK4/23X/J
   3.122 +T4cwusQhBEIktBDx5Kl2YcCKpuPJIX/ud9EpB9DfO4IYoCLr7NqZAD/m0tlFcHvX
   3.123 +7UIVygDy/Fa8m5NFUp27gfYzIPhDtIX420w0+tGE+2j2DDiZ5buonxlWboSSQtUN
   3.124 +UfU+RNs62iCxWBDChHDQf4ssu1Z9s5f1bpRQ8D/2bl+qbP+tIkVHA1Z+X3z110HT
   3.125 +Nvvm+fWyeHJC1O8VnGgafjZUP5bi1mKvr4VUFeArsOJYQIj3L0TJWHvE3LPs4YnC
   3.126 +2rzLO9b95dtXS4oRUhHbJ6w5x4B7J/2eV/7XiR94iN5glXEC39oXU3/LezoPlcTt
   3.127 +6nbD+JUrqiD732rz71RCb2F47bj5L9sSz+IzrL2pMf/JckEH6wZpx2SFajZ9c0qz
   3.128 +DTeupjEC6EuOy5Lzs+SA7Jg06UqdYeu++AtHpyABPnLITiL3g4JHinpwuMUSAD9h
   3.129 +Y+AbkqnLr8wPFTzP5+Ve51XBujHfVR3hJCbjZg5Di9PpslQPQZeDmwshfb+eCajw
   3.130 +TXp7j122u7M8/34tLY4YhQ1eEI84pljdtTD9zBJrlzpfp0BsOG0eM3RQvi8eVxvN
   3.131 +TolH21uyMvC0aiRhP/zdyqQQ4WAuF03kzUPVpkRl/aUYOzzWm90JOUyXIVsTRa3P
   3.132 +M8DAxSp8FlNL37fCoRub++x5SDZlL9aXYaEG1xPlz91weRFVNe+OLC26g0Ftjc+h
   3.133 +TT+gOxFSyo14XZdYTndqJjtVLYMhxwNBqxVlac3OFMy0X9lq1sJuWF/mWAC3vdsV
   3.134 +lZHgInVKnMlun+YzP9obRJlej+vBU9oURsjkFeCnHY3F7BzK3mTFok1tpCtM/U9y
   3.135 +0pKNiU7frFenBsIpHSK7ZRolpOxlNA18qyseh6mLYJxVrTUCNKz//FHg07R45j/6
   3.136 +GtKx6/JCEWvE/T4xHRaSisXRgQ6gZTLMw+s/6S9bBqbBbTUmUribnSqFscOPc6Ao
   3.137 +HR/fN+sAIduMRElf6ivBqcYm3ced7BSdJIuZv/I/V8Dl6YIFixpeqh2mlvh055RW
   3.138 +9INqkwPZv9BbXyBAS7VjeWxgUcoX3OXnHoxrs8VOV3U5B9wpHemxInLbk/7OnEr+
   3.139 +fxyldbu4AeVkO19IiLTJzw1oWe2Brg9wpoNobMAOnxQdBrCTfNB1JfNHy4efdquP
   3.140 +QC65GkJ9rW/KmMb0ieyBdXLbJdb4Tj9zCXNKmvgBD0Xf81vWxRv/dq1f1HphwXSs
   3.141 +PyKcEHy9yqlMUaTwGK5ib7T8Wayu0+KMNWOQrlin0hWAjLRLrS4yWmJwXXfmLmp9
   3.142 +hUTqA91ajLN+5b/zfvp/+Gl1RvadsAkY5ChO7NkRuLTdywfYiR6XxklCRcr3s+Su
   3.143 +H8AVSSPjmWIXyVdRKd96lPAlcx5DVbq7BWIyjhcrXwmslfyNors6pmXgWCirDtjP
   3.144 +cnjzUI5ouxD9jGC47GsMfGbj+biyencMP+MFZbAuQ7mpBnqTMCFcYX8t6l5m3mKO
   3.145 +wMgI+YfkVfcnKiFRNEiq/2Swl5w/LVAJCYjcQ377MZyXdtF0pH1QwWWKs3aC9SVr
   3.146 +YBRqWNnVWPQY5H/KXYFxAXqv7JP+71ioT9JW7NArqnQyGQbh/mO/PDBAHXeyXAkv
   3.147 +VIY23xqhwtLNN7WclHQUv7Re2qHq3ZGWhg81k9yu4MH//ycUufPGoxTSBZ2oSumF
   3.148 +frMh/pBE+GihChwJ5EDjORnK3eM+0ZBmOyaKq+1yGH3v1c0LKdulXEUjQLTA7Ycl
   3.149 +oS+su/xbUoKJexx/Wqoo4K3BC5oJs0TZUK70kuvpTqRNBAQFCnIgiqqyk+6sIvBS
   3.150 +vxfdrBGWM2pqZhNiGwcHTH8E/MBZUDiI2++Lyzt+2BBYO2BdkUohNy7+ZmguGOPG
   3.151 +Gl//BzAhaUC+AxT49s1VRTZYQu59UdyJywAbalkIs/13igVQi4+e0r65KQYKcHkE
   3.152 ++gHjz6nTcgK6syJLJAkR1JRqVYND478Rof+1W7PCIFv+DuN8J9eVcUU+/0jJk+cd
   3.153 +LoNyaORXNyxPGAvhbZtfrx65SF9Q43oWATq4OogVQf0r88G4u6/286Y5JD1BQs8J
   3.154 +AxGLofgCJWCHaujzy6Gq0u/+4mehSyqY6icWSQePxA0VhJ2DU8/Wurx71Xuri2YE
   3.155 +z7x5nNZzUYf3/JpLl2QaxKlzxIEWqurSsp3blPwzeZVCdYOZz7a2glUgqKugCxtO
   3.156 +Va2ikY5nfj3cmurPsoDC4IEZwIBScwnKUK9Lqz4LwnrpYiz7wmyrYfct5t00gJZ5
   3.157 +dSbPWAW2SAkpqLMcExIZFAulSs21a718VtJgtfRVheJS08fS2+c5n9ot8Esy9AJ/
   3.158 +YxrHNwaRYVGoUEXXZ64AL2r7hsJojmK5zGppRq07PnBacsNh2SZLdJZlmcyACuPl
   3.159 +knRrVm+op0EEyAm+FLr2Ko438FDaHRvCJ0BDG4jXUz4WfbjNGpZ5RRpET60xFFJh
   3.160 +TFrH1q0GrWGCt8UXOOYjPgsE6KMF8ZHSHetuOHsf/bytn4hU8RklE64Ur/lLRjhQ
   3.161 +A8jaWidabnDJgCTfZtVGOpJ2E8VvxMrBBBSyRUB+cy/v86oc5JWCGVDKzKBOTHyj
   3.162 +hUJtuwV5uBHxL16R4cEoKarBaFnE+/k41zOOkKQYlWsZAD21ah8s6NS7KkEXd9K6
   3.163 +oxDt7WGoe6W1VfjNYoJRgZTpVCZhNR/CkDbUL7EATfGL64/wSz0FSnNIqmmRsJkA
   3.164 +05x5j4kKqRmgdMQ2OspLJ1qgvdmciIYsaclfEQnHPqTCgh6BjK4g2PHV/ja/bINa
   3.165 +RcP+J0QyWsswORYE2WqwqLucT7Tyhqi+BhW3661MMz7yekACqRHUCpwtpa+dusek
   3.166 +wFKl5MA//2qWxBfJTq90+13aHhOWq80r7MnM91LpFhCca6CestV5v3J1L8kRFfS+
   3.167 +hi65dZez132+VW9P8xN2mRekYLMzH/bvGC8ksOnFa812FxHNywNv5xasgSggH1uZ
   3.168 +xu8G6soqp1A4u/1mavJxTYzvfakfsExfV4VCttKcdZzxZUQPm3c0EYF1zKdeD4ld
   3.169 +HYw+PULXM1vfVPzn7v/cdbieUU+5OWDFzgSdYbWWOhaSPfQIXDDw9xRuIDgL67DC
   3.170 +7q4i7gk81iBS7y6tU2jJWDECSex2qNLI0TqqTK9qKn04BXV8OikhO/nHQa67+WPP
   3.171 +JSZohy2b+rqBktZbrMv1GvEiqmWLxdCBS7vsR6XuEGKR9aXyklOcSzmHGKdfPt/r
   3.172 +o5xjREBMNBhJcw9t/1iOoN/cewHwT2EQlmpt8f35kj6fUEr3xpE61N6fj+zxauhK
   3.173 +K2Af/4PCbcFSHSBUj1Gzue8ddSOIbJflJOp38NMUStEr4X4Bu2uKcE7jS2452Pop
   3.174 +22TArAqYJamMXxWBjVSgl0so3ldO05502TUSMNF7iyJ41lVDGZJM69fkt9JnjTCq
   3.175 +YXYQ22banpS5hDVkJzT7KH/1hINnw/JWIwMNt2Jzoo0Mvcg5vlMQNrcKX9bNeQGL
   3.176 +KwoZg1XBSYyxMwpLqN2AY4T/TYRaMF3ArYNWhxJoVJPPe9FvgzZu4371JedyXFVk
   3.177 +iY5XZD/uX0AxllCn7MPe2Fb4smW1J+PWp8UW+LrvK37OrWIiXBnDofsRb4RzL0nB
   3.178 +hhB+sAfTqFrGEoWFiDYmKNPgtNUbKFmwLNTnn8ZqianA4Ucn0/7bBe2hIUQuTxaP
   3.179 +jawHIFn8XLrwIAG2aRQg2UiaYupuCONUfEACaKql/qEyrQ5zyaiRiyalVU8JlJZ4
   3.180 +vFKzN8A6AaDV/ztzuS+M8p1bGFtQGDl0oS87cKRufgyPcA2IXFvAmxmITDSQL3xn
   3.181 +4y9p6KcbUpWVNe5PuLUKAUv1d/EYZLrNOWuXn/P0fhc=
   3.182 +=QAOv
   3.183 +-----END PGP MESSAGE-----
   3.184 +
   3.185 +--1bf5eb907b76716d2b9eab6525e9c2ea--
   3.186 +
   3.187 +