sequoia: Add support for importing revocation signatures sync
authorNeal H. Walfield <neal@pep.foundation>
Fri, 10 May 2019 09:11:59 +0200
branchsync
changeset 3657ee9abaa0e34b
parent 3656 a2f10fa2843e
child 3658 733edb269d7d
sequoia: Add support for importing revocation signatures
src/pgp_sequoia.c
test/include/RevocationTests.h
test/src/engine_tests/RevocationTests.cc
test/test_keys/priv/pep-test-linda-0xDCD555B6055ADE22.rev
test/test_keys/priv/pep-test-linda-0xDCD555B6055ADE22_priv.asc
     1.1 --- a/src/pgp_sequoia.c	Fri May 10 02:25:03 2019 +0200
     1.2 +++ b/src/pgp_sequoia.c	Fri May 10 09:11:59 2019 +0200
     1.3 @@ -82,7 +82,7 @@
     1.4      pgp_packet_t a_userid = pgp_user_id_from_raw (a, a_len);
     1.5      pgp_packet_t b_userid = pgp_user_id_from_raw (b, b_len);
     1.6  
     1.7 -    T("(%.*s, %.*s)", a_len, a, b_len, b);
     1.8 +    T("(%.*s, %.*s)", a_len, (const char *) a, b_len, (const char *) b);
     1.9  
    1.10      char *a_address = NULL;
    1.11      pgp_user_id_address_normalized(NULL, a_userid, &a_address);
    1.12 @@ -1656,12 +1656,70 @@
    1.13  
    1.14      pgp_tag_t tag = pgp_packet_parser_result_tag(ppr);
    1.15      switch (tag) {
    1.16 -    case PGP_TAG_SIGNATURE:
    1.17 -        // XXX: Implement me.
    1.18 -        // assert(!"Have possible revocation certificate!");
    1.19 -		ERROR_OUT(NULL, PEP_NO_KEY_IMPORTED, "Implement me: Have possible revocation certificate!");
    1.20 +    case PGP_TAG_SIGNATURE: {
    1.21 +        // The following asserts can't fail, because
    1.22 +        // pgp_packet_parser_result_tag succeeded and the tag is
    1.23 +        // right.
    1.24 +        pgp_packet_parser_t pp = pgp_packet_parser_result_packet_parser (ppr);
    1.25 +        assert(pp);
    1.26 +
    1.27 +        pgp_packet_t packet = NULL;
    1.28 +        if (pgp_packet_parser_next(&err, pp, &packet, &ppr))
    1.29 +            ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Getting signature packet");
    1.30 +
    1.31 +        pgp_signature_t sig = pgp_packet_ref_signature (packet);
    1.32 +        assert(sig);
    1.33 +
    1.34 +        pgp_tpk_t tpk = NULL;
    1.35 +
    1.36 +        pgp_fingerprint_t issuer_fpr = pgp_signature_issuer_fingerprint(sig);
    1.37 +        if (issuer_fpr) {
    1.38 +            char *issuer_fpr_hex = pgp_fingerprint_to_hex(issuer_fpr);
    1.39 +            T("Importing a signature issued by %s", issuer_fpr_hex);
    1.40 +
    1.41 +            status = tpk_find_by_fpr_hex(session, issuer_fpr_hex,
    1.42 +                                         false, &tpk, NULL);
    1.43 +            if (status && status != PEP_KEY_NOT_FOUND)
    1.44 +                DUMP_ERR(NULL, status, "Looking up %s", issuer_fpr_hex);
    1.45 +
    1.46 +            free(issuer_fpr_hex);
    1.47 +            pgp_fingerprint_free(issuer_fpr);
    1.48 +        }
    1.49 +
    1.50 +        if (! tpk) {
    1.51 +            pgp_keyid_t issuer = pgp_signature_issuer(sig);
    1.52 +            if (issuer) {
    1.53 +                char *issuer_hex = pgp_keyid_to_hex(issuer);
    1.54 +                T("Importing a signature issued by %s", issuer_hex);
    1.55 +
    1.56 +                status = tpk_find_by_keyid_hex(session, issuer_hex,
    1.57 +                                               false, &tpk, NULL);
    1.58 +                if (status && status != PEP_KEY_NOT_FOUND)
    1.59 +                    DUMP_ERR(NULL, status, "Looking up %s", issuer_hex);
    1.60 +
    1.61 +                free(issuer_hex);
    1.62 +                pgp_keyid_free(issuer);
    1.63 +            }
    1.64 +        }
    1.65 +
    1.66 +        // We need a packet.  sig is only a reference, so we just need
    1.67 +        // to free it.
    1.68 +        pgp_signature_free(sig);
    1.69 +
    1.70 +        if (tpk) {
    1.71 +            T("Merging packet: %s", pgp_packet_debug(packet));
    1.72 +
    1.73 +            tpk = pgp_tpk_merge_packets (&err, tpk, &packet, 1);
    1.74 +            if (! tpk)
    1.75 +                ERROR_OUT(err, PEP_UNKNOWN_ERROR, "Merging signature");
    1.76 +
    1.77 +            status = tpk_save(session, tpk, NULL);
    1.78 +            if (status)
    1.79 +                ERROR_OUT(NULL, status, "saving merged TPK");
    1.80 +            status = PEP_KEY_IMPORTED;
    1.81 +        }
    1.82          break;
    1.83 -
    1.84 +    }
    1.85      case PGP_TAG_PUBLIC_KEY:
    1.86      case PGP_TAG_SECRET_KEY: {
    1.87          parser = pgp_tpk_parser_from_packet_parser(ppr);
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/include/RevocationTests.h	Fri May 10 09:11:59 2019 +0200
     2.3 @@ -0,0 +1,22 @@
     2.4 +// This file is under GNU General Public License 3.0
     2.5 +// see LICENSE.txt
     2.6 +
     2.7 +#ifndef REVOCATION_H
     2.8 +#define REVOCATION_H
     2.9 +
    2.10 +#include <string>
    2.11 +#include "EngineTestSessionSuite.h"
    2.12 +
    2.13 +using namespace std;
    2.14 +
    2.15 +class RevocationTests : public EngineTestSessionSuite {
    2.16 +    public:
    2.17 +        RevocationTests(string test_suite, string test_home_dir);
    2.18 +	protected:
    2.19 +        void setup();
    2.20 +        void tear_down();
    2.21 +    private:
    2.22 +        void revocation();
    2.23 +};
    2.24 +
    2.25 +#endif
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/src/engine_tests/RevocationTests.cc	Fri May 10 09:11:59 2019 +0200
     3.3 @@ -0,0 +1,59 @@
     3.4 +// This file is under GNU General Public License 3.0
     3.5 +// see LICENSE.txt
     3.6 +
     3.7 +#include <stdlib.h>
     3.8 +#include <string>
     3.9 +#include <iostream>
    3.10 +#include <fstream>
    3.11 +#include <cstring> // for strcmp()
    3.12 +#include "TestConstants.h"
    3.13 +
    3.14 +#include "pEpEngine.h"
    3.15 +#include "message_api.h"
    3.16 +#include "keymanagement.h"
    3.17 +#include "test_util.h"
    3.18 +
    3.19 +#include <cpptest.h>
    3.20 +#include "EngineTestSessionSuite.h"
    3.21 +#include "RevocationTests.h"
    3.22 +
    3.23 +using namespace std;
    3.24 +
    3.25 +RevocationTests::RevocationTests(string suitename, string test_home_dir) :
    3.26 +    EngineTestSessionSuite::EngineTestSessionSuite(suitename, test_home_dir) {
    3.27 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("RevocationTests::revocation"),
    3.28 +                                                                      static_cast<Func>(&RevocationTests::revocation)));
    3.29 +}
    3.30 +
    3.31 +void RevocationTests::setup() {
    3.32 +    EngineTestSessionSuite::setup();
    3.33 +}
    3.34 +
    3.35 +void RevocationTests::tear_down() {
    3.36 +    EngineTestSessionSuite::tear_down();
    3.37 +}
    3.38 +
    3.39 +void RevocationTests::revocation() {
    3.40 +    // Read the key.
    3.41 +    const string key = slurp("test_keys/priv/pep-test-linda-0xDCD555B6055ADE22_priv.asc");
    3.42 +
    3.43 +    PEP_STATUS status = import_key(session, key.c_str(), key.length(), NULL);
    3.44 +    TEST_ASSERT_MSG((status == PEP_TEST_KEY_IMPORT_SUCCESS), "status == PEP_STATUS_OK");
    3.45 +
    3.46 +    pEp_identity* pre = new_identity("linda@example.org", NULL, NULL, NULL);
    3.47 +    status = update_identity(session, pre);
    3.48 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
    3.49 +    TEST_ASSERT_MSG((pre->comm_type == PEP_ct_OpenPGP_unconfirmed), tl_ct_string(pre->comm_type));
    3.50 +
    3.51 +    // Read in the revocation certificate.
    3.52 +    const string rev = slurp("test_keys/priv/pep-test-linda-0xDCD555B6055ADE22.rev");
    3.53 +
    3.54 +    status = import_key(session, rev.c_str(), rev.length(), NULL);
    3.55 +    TEST_ASSERT_MSG((status == PEP_TEST_KEY_IMPORT_SUCCESS), "status == PEP_STATUS_OK");
    3.56 +
    3.57 +    pEp_identity* post = new_identity("linda@example.org", NULL, NULL, NULL);
    3.58 +    status = update_identity(session, post);
    3.59 +    // PEP_KEY_UNSUITABLE => revoked (or something similar).
    3.60 +    TEST_ASSERT_MSG((status == PEP_KEY_UNSUITABLE), tl_status_string(status));
    3.61 +    TEST_ASSERT_MSG((post->comm_type == PEP_ct_key_revoked), tl_ct_string(post->comm_type));
    3.62 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/test_keys/priv/pep-test-linda-0xDCD555B6055ADE22.rev	Fri May 10 09:11:59 2019 +0200
     4.3 @@ -0,0 +1,14 @@
     4.4 +-----BEGIN PGP SIGNATURE-----
     4.5 +
     4.6 +wsEBBCABCgA1BYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWL
     4.7 +DR0AVW5zcGVjaWZpZWQAAMQTDADVJWlSCAdAkYixuNih9en5BHflzgfSDGgBqUKZ
     4.8 +NZ+FQyHqWLy6gkcZaXPOKz5PbMuygyPqvRvJtwpYXpGoI4gLHi/YyN4UTQT8ZzcH
     4.9 +wQeB/TZagrnHx6oKCKxnQziQGUfZczxRSAl2iL0f1geZ1kL1Czs0qH16I9jQU1MI
    4.10 +z9zgjYgKPmucuWRj/gQdS4SI0z+m4ZM5YkbhUC7njv18Qya0H5JS+7vn81Up1+9j
    4.11 +IJwVVCI0HfFRWA3FPCZBuY3CyTk40xmHvBWm8/b/YQkXJOJxsSvNe95jvHSHyaVQ
    4.12 +jlL1QYhJigp/fzQ/wDpB3ig6PFlpJa5CunWTJRj/NTCWoKKDhWtnJlDSTLIw/sdE
    4.13 +U9hMAR9rFARRRI3IFfNQdW5fsYtka2Dob+x63kMBoulfbdpf4pz15zf3MkZL9F3m
    4.14 +ZOYmcL88HXGjnmLTVeKx7fJMGBzpsXbjbULjJrJsRQbFfcqJqUN4p9cIiunuOSWJ
    4.15 +fLJXpEV60hLvznXS00fVFmsAGBo=
    4.16 +=wskl
    4.17 +-----END PGP SIGNATURE-----
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/test_keys/priv/pep-test-linda-0xDCD555B6055ADE22_priv.asc	Fri May 10 09:11:59 2019 +0200
     5.3 @@ -0,0 +1,139 @@
     5.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
     5.5 +
     5.6 +xcSYBFzUGDUBDADfcLC79rkUBAKvkYtZ3Gg+rPXCIL/7PKB/MPa/Mt6hwCRuQLSZ
     5.7 +O0SVAcBhIwNiWNmQAQx6YKN0niCw3fPoTg+KyVqn6zlfRVUZOHOUCqGZrqAI8k0U
     5.8 +ZgJRy3tC34L9F4QsLQ0MLFBC4+Yh+Snv7Wb8zdIqTKDR/jCny2SF7jULB/noQ7sG
     5.9 +aVSyXoZyBIgvWUoBnhc/jYzfUtRHccaow6BA3ZbG91yM21ERv9IgxYIMZfdm38oM
    5.10 +/pOEhRXDce+LTZ37cDDKjqOWi2o27AEHR8I9ofV4ZifBgf9pxUjFn/GNOmLI4rk/
    5.11 +PIc6uRSpkShnQXcFsIKAqaWbquxOvTrR/wrDwz+k5lziuUZDm3hHuYDWYA671BYg
    5.12 +SBkmQNqkOPp7Vbgqzw4xLt7jQLxV8o3DDUme7rwCfuDUzcn5pgl2IuxD9BXuz+m0
    5.13 +97mD9oJs/kwBozRXupXXzx6gU1OC/M0FFzHa2TlUgQl1CSY6JvidO0r/anbOgbGE
    5.14 +0eH7zmQImSjIuBsAEQEAAQAMAJmnWSIpTKUjDOXHZNjq5RUUw/w3oU4YJxbQiR56
    5.15 +0PbStzrKbGdjhoohpjYmadFb4GFTF02g30b25uw59d0usSlzxk/rRozplNe/JlwL
    5.16 +441XtN3yImeArt+o2p7mLaH2ZgIrCOnyH0+ggUWjnt9LlqMKtxg3kfBWqQb6q6oe
    5.17 +YYOwfH7o9Ng33vK6ZiJKU4ycDnSGTt55bQK2ZxyqdT7hKHby6xjwSkjjGSDnlIzM
    5.18 +xd3Y0QWBp+S/vJpJGupIk75sJIsKruGjX09lpSMWJG0aG8XGvGrAF/RWUs4OSnrp
    5.19 +Aql0qq1tiCujzQ/YiESLqz1Bdp/fCNMmUPqLuKyMvsDehznIvNxzRLxplIXBNqhb
    5.20 +ZWh98mknYxi1DAgk+2X5Ocilvgspn0a0TSfuT6cLC/CDYnUfPZfviY35A/JIm6SK
    5.21 +i6dEWn413F+Vzvn59LG++Ue4dQwXwUqr8HrCDk2Cllk7+4bfhWZMwPzXus/d4erK
    5.22 +248NbiDxtpp+olILs1pEVlt1YQYA6DfJSK2VyscOmlpKu0rwP4eq6rDHItviIDhA
    5.23 +y6jdCGe9b/C6G4397q4IKy3aM2zhsBizYMfAf1OXuoOiHf6ZR5bLTDI6DA0bI9mx
    5.24 +wyGIKoIhXI+59PJaW2ENqqJvljW8PpjdMf6gJq9vcHf6AbvceHSnBHdCZgmKEUg4
    5.25 +Q94DZbY/FNKradCFFM9+mKrLNzXURYVDotiJ19MnAJq+G+qG1skKBwqyF3An183X
    5.26 +cdp504smbANyyVmKv79egpCpb24HBgD2UsXSQQXfjUGAMckutU/HJgaQLqXfHmfJ
    5.27 +vOEGgposfI3uxJFd01c4ssa18RB8gvgqARhjWLnpqzi4o5hOxXsva+wr5YxKIO1w
    5.28 +kQNss7Q2g/UaOtDRyi/1yfIKCOCLGyyzNL8AqvDBi+r10qCvn0CdI+KOTZd+f3Ba
    5.29 +clLQfMHeQ6VZopIsDuDphgrrjJWWi3n+L7N8QWJfSXpU+yHFPS6Z2M/FsNRqBaYG
    5.30 +DPU5B3yRxXkn5WEV6o5C9FbDc05uYE0GAOdda4hWbEoMOJLFpD9BLOYGPdEwDoFk
    5.31 +cbn9HuCf5yhWATJevHKcZ8p0QtqyGcO1MxhnGKRE+MEBg/3K5PYuNHiFVWYt7UZ+
    5.32 +Ppd9GHCztEEhhMT1Loc9wLoUyn/DD6OGw5HJr/jQwEeQVi+hMAC/8XCvPWkB3jgd
    5.33 +kV6Pp7O9/xQwNL+mMoKnWDm872riUA7GNztdKnYNlzEls4nCyfrFHWPrsygpLnY7
    5.34 +c3hGaGIaW1TvxhszjhMGimY+bfR4aNYJ7eMcwsECBB8BCgA2Ah4DApsBBYJc1Bg1
    5.35 +BYkFn6YAFiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAhUKAABmgQwA
    5.36 +2ueTnP2ki/cEPcyxmTpl7PAVSaxRqxEpEa4lofjklFbOhaGrOsfbkQvINAYhMoXP
    5.37 +xDTNj0VrRf+Ffv1FACznkG2Tmm6U255HfmJjdlHICo7yKOcoMUvifgURcx1p5nbF
    5.38 +F9r/AUWRg9Cz9VXrnUJnnCZqd1AZpz1K3NlWrSlAJJmtAgXIqX4YoWoJwhj+pKIT
    5.39 +hDSF9ozKWobN9A7HCkLwk5JFh690SSCe/X/Nl1rUXd+jXlor3OKdojvc4BPOBURE
    5.40 +PSJ/GqaGrkELLGQ01LF17ThB9XCfSPh3D/wG/UQR2T+FckiSdpy4jidWN8TgqigD
    5.41 +6zFzSveXswWiFk8+OKmtVN2NTcOCsO1l/UCgiL8pYG7OShJvhBndd9pCT+R6mDNj
    5.42 +IOTSdwMPNag02zFAFRCv2hXn+lgJczIy51r7ev7ONm7fF9AHZLqDqH/zWyfFQjdo
    5.43 +z5TKloHl3fZze1sphv3isUYZkA9gOeYjAj1g0A9dAvxPGLC40E1a/20xiNZxP6UQ
    5.44 +zUlMaW5kYSBNYXJ5IFBhdHJpY2lhIERlYm9yYWggQmFyYmFyYSBTdXNhbiBNYXJp
    5.45 +YSBOYW5jeSA8bGluZGFAZXhhbXBsZS5vcmc+wsECBBMBCgA2Ah4DApsBBYkFn6YA
    5.46 +AhUKBYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAADAFgv+
    5.47 +Omxaoo3pQVZJ4nrBOBiWJvEQ8fUTjl3VSTzE47DihWcCJQurlI5yB6yvtmuYvQX0
    5.48 +glIKDPBKJXx5Rf77MnOFcUcD6mA4r7Oyi7ke3LNWP+L6a62ueUEvY13DWNeHmohW
    5.49 +wz25pDvoBLWuUWyOYAzvtwoMgax+uaLVXVjwvV8Xrpaexb+5mD4JFrxRVdjJapcR
    5.50 +ls4iwEbkOv9i53frQ8iIeLBi+8LI00Kz56o4ztuGf5i3bjho/Ju/ubGWTLjJXzKw
    5.51 +TzculGpNUeu3fHJrjqTUO/1jkko0ndi7avdYlgyuBE8G3uDdzbGYEE04kLYmkV6q
    5.52 +wKySlTg6h7T+msv9uN7FBJ1U6vhzrRorKz/pLbLynT8zX5ZMwl0uC+UyNwfUZanJ
    5.53 +SJ6cIYWZ00EiJLipQx0wkImRGQ77viUNKoVD4i9taBLVuPJMp7E0sXQ9qxHbspDr
    5.54 +XlXy+XaeD+rr9fhyGKBxfSqGe1HJmBWvhXWSwHateLuHTGO7qn8GPCK41PMMyeiA
    5.55 +x8SYBFzUGDUBDADPapA35r7ZPQFkVLhCI5sAp6eWOD6OuHXABcRHM705zfeaxoB4
    5.56 +PZgvziedFy4gxTdYwkcN1fL64kRVZSOGlQD7/QDO1JaWWAN+zaT0u6XVVpNRd5vU
    5.57 +5QtUDGb9QjIfwpWSXDmQdrjrVJQ68sSLIogAH1itvo62hl2z/DKqnRJWQDx15tJX
    5.58 +4RUAkyLzn1HfSEuTFm0wETfj2eKJECKtEvsIXe13eWkuFPI0dLWkIpoGGVV6jOZw
    5.59 +RcZ3QqkCU7xoD3WC5p/XXm4Lpq918skMt7yrgV3IFz7XuDkuMXtIYMa8e3Zx93zK
    5.60 +p8rFv5CWozozt7LLdv7kx6lwD+oAcOn15ZQd16mGoU3q27KJRXPTED3JfkItc/pa
    5.61 +H+g/uJvN50LpYu+n6UeCvLSmTtBrGRnCc1sTOJfmLfl1aZotSM5Po599hEH3/WUL
    5.62 +PMfoCAXk8hPlb7yblEOc/cVbE7KCXCjM6/bvlzUw+tMWbzpPX5qxUNdI4Uw6ustZ
    5.63 +tIb7phJsfTNDTTMAEQEAAQAMAKwf8MKTODmrCKasL6SjS5RFjSt6TV++7+iEYJf9
    5.64 +9cAsjpfgtugRpWO2nuUcQWlsgDumLbTroZJVhwOexNaAfKqhELSTcswdCfmGyqdV
    5.65 +uY7LI8HtkmIgGUCMckMlVddJcTpeUl7yRw7zx3cL09LquxXu7XZxtpj99HDSj3FK
    5.66 +m9b7w7DL9i57WSR69fxacGTs59qON9o1z73EKNw5ia07HRuaZuBI3uIg+8ZQPBST
    5.67 +qmH5UBg9KVZucP6zUPHfb3Cjsg8c9Obu5D9wHueXRz9irQcDM7UZ5W7ZQyaHL8cR
    5.68 +RiOMOZZQYkd6AG7Gh5Ta6uhjEPDko5uIgcCmn5mCY6Jxr77A4IQDN4l6tG3xvTUd
    5.69 +8gHsEAGKKMCPhwgf8YusO85a89oSdyyBZfJ9E7G0lpkQZa3MZVura06FcAN+ritP
    5.70 +7mKt4qeasYHpSrq6JdvoqKjI0IJssNbfprz1w9zCof+g8wiw24QUckqNEVYdGr6j
    5.71 +AKXZFQvQXR9yVZJLDsnLWiKjYQYA0xjzy55Yd1QwubLiQzCysqEOzpvhLC2wTnnH
    5.72 +IkEcO97U87ALQqI7/mUkMIuIChOeP1v2z4Djb6b+FA7OL94J/3UInz0sktBKrAXc
    5.73 +qm4jpPtxNkmvZStviZtoZOfyyBj02hIqNVFKJhgkct/nmVbefMQkyEjAVDF2F1Ph
    5.74 +802wcSjuB7J8ZcT3fRM0sU8WVydcVeucb2/+TEa/YGeiRJfzBqtgvtuPSnBGP5ZW
    5.75 +u3G8Ro+fee7PqiPV8zHVBLxo76xLBgD7iSfQkt8uwqA2q7yxeX/ZQyUIbJB0xCFz
    5.76 +W9RHQbYia9KFE4V9dSnRO8wicwPCOekEKqzz9YhJQUvL/TOsGLgy9jVyNsjDNusk
    5.77 +XMTet41AIcQIQrY6ZvDIFMbUJpAub+FX4Qf5hu56lqYGjOyen7eJ1uqoZxZYOQ+f
    5.78 +1WpjcWMQ2v8vY7qPofyWzbBnBFIxJCdR4daZaOxAGa5P/Pw8pKA3Ha+53in6fHa+
    5.79 +bTzdBOz4PNsYTfEMdSGkgCwFzqX6gbkGALRuP2GjBLBvKqDlIlJW8PQ9sy5vAV/C
    5.80 +SDb4gLJiQHXBOwR8TZdT+xGwUbJMNdZlMUZvK+9B0vkhOF+CZBUqpi3uxfOVPWIK
    5.81 +HoQwlbO0yeg4bv7NxboAcs0deszqhmQ92BMOotfmPYKO6naARrNnjJPnYhJ8xzw+
    5.82 +gNfS6SZO1l6NzDxvGzalXMHPzUzeI6AdwjKkvgnMt8Kg/Uchp1PBzJ/63w8ARxFt
    5.83 +ezgC05cVvu89KSNRrd8/Pv20LGkwX5Fn/edOwsECBBgBCgA2Ah4DApsMBYkFn6YA
    5.84 +AgsJBYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAABXMgv/
    5.85 +Tbmv1/UgRff9vRETEi9f4rUYOsvX5Ay1raRBskl52JLbGmkXI3SeOjoL7wv3xzI1
    5.86 +ieIEdpyxcJNQG9n9Jfvs0qqXwVisnljRfWckmEzu0MWqpQtKmX66naOXwNJjbmnZ
    5.87 +CV+WgWHm8VsC2AF3QkP6XnunIsJHwL3yMfNrg3QA7dgJusEJ3AGG7elGj8UILLdX
    5.88 +VUDmQnPcu20aY8vNWxadUkIm2J62ahk3oeb0JqVS5SnxBd5ZWSj9ds2LE/v5Q3Qx
    5.89 +RFpo+IcNQ/aUDMLiEHh4J6qW9N/1lAPedBW6vCRtLLXworhTb7ki/+XT4Q6MFzF9
    5.90 +mEDX+DP8NLLFSBl9C50EhDle5yVjtfMeVFYczaIRHCuumY3o/j1rGS/lP/Tk7aDI
    5.91 +Yf6yfHeNJPdUzhnumZqXmJJxSOQtVm0avPAeuA6T23WLqaV9KIUhpdno4YYj/H0O
    5.92 +TbTYReoQrRLbQ0nQHRJVXMhoODQq4frKyP8nQ1DhYnDBj47oD4ZDhI+QuxiCVO5p
    5.93 +x8SYBFzUGDUBDADgdeXRNfdimkBUtMNp2LkK54n24C++P/gyJmRA31hrw/VJtk4P
    5.94 +jvUT3E1+lVr0/HyPQVcZJr/L+RO1HaYqETq0inJL/Y0o2L0Ky7Y/VRoLKBdYvjny
    5.95 +sn/3pCBozj8HHuyMre7ORW8vxE3QliQkwUbqC80Lz3tiyXBJ/0bN6skYRHdLKE/5
    5.96 +C1ou2dBDeib7xNlARcpa40tzdvPu/j+H1HyeV/VOrK/CEzFBTAWbb7IJyUr3PPl0
    5.97 +mU77BOSa/2OS5HM1sDd80MJ8pjqhJxprBxa+9gkgxUbkq8lDo7M9IsoHDEAsrM0s
    5.98 +mJXCDqP7Moz8CB7IQC8aOVtWXhs4TbTe5xg4lB0Q91GOE82Zu3j4x4GeD2IhUP8g
    5.99 +TqjgW6v3KRMo4pEYLa2Q2PXWKYiLT0ZgAvmJfIAeMzo27XVMx5SDhQd6jcVMiDa1
   5.100 +qtbUOW/34161zInSJUl3mZ6AQc48lYsdD53lLQE0RR/oyYzo2wDhUbnpy7TmrAnz
   5.101 +K14AIUoeDLsTi/MAEQEAAQAL/3vd0/M9+sT5JqMYFfalWIhB+gq48N/mYUsbkJuU
   5.102 +JTFjNEt3RWCknW5WVpWSSl2DsCFGB5Cjp5giXdPHBtmUJHdZJ3Xz+CAga0I35NzS
   5.103 +U8rwVuHsKAJcqu24LwJnPrTpRdTkbzJ5csBDbkW7dTqrRj0GQiNQXmDHlSXgr+wW
   5.104 +st6necWJ+4gN0bilDp8OG9E4ckNbwC2j3RFdBYRP3jNQ+WxQUdkWxu8stDO6hiWe
   5.105 +3/sykCIcDfVgXQt9ScKXSRXY5wpfthh3dASxyUlgM6DtA6wm4I4XsHdjrZI/Bre3
   5.106 +wTKyrZ42WnwVcFk0MlE/82uwaj5zxZp3fdfLG1b0J7raCRftBy3uYMhExKBicv7t
   5.107 +y/eBbm3/lKswUAP5aj8HmDd1MpSaaCl6A1RGMNEeo3klL/Bz8FL/QLSxPemLArm1
   5.108 +HN4x3lbDF7Ejx9bWTA93UVoGUis2uQSuuNgQ+Rx2G+Gy507ydn25tmNgPQeXLWqn
   5.109 +kotX3C4542J4Z6F+BJ4us2jaoQYA5f0ULMGDRf5VWCemYSzvJSLxk7XA2yBrUAbr
   5.110 +riUk1ZjFuEdqHTBzq7LtSxbK9ICP/chqImQuIk3wUaht1g2GaRX+R0rblxPi2DUu
   5.111 +OqKFETi3izGJ4xZqipA4pSFsmVNZnO5XvCTAbT6SCsjMlHqx/Xrkn5EGcAKkxStY
   5.112 +8Uti+i054Hr2qPDJonb6B6RESjOEZ9KhfDAbIm82MOu1o8LRKZgedKEeEBys+/AI
   5.113 ++lnimKbHWBT5NFUY9RLJsEt/415ZBgD52MOGjYX/Rne7AeGTsZrfY03D5yTe3DXj
   5.114 +U+SL9Tcl5l+0thObux47atKNfih4uscvnnz+FRQt0C8wqWRucRd7C66PFMrcBQy1
   5.115 +1mV2GByMvmM9TVmdDiV5OCyadTsPRfuK12O723XLJ//6WYJVTZO9+yy1v+Q3I8N/
   5.116 +8eFbqlsoxMzhGvqt1iVpm5fx8yGaP0dndPTxhK8FW3DVt4HOwokw5tvA9K/T1+UQ
   5.117 +zeIES1gqv20RZlcIOmMK4AYOAIef6ysF/RQzXAdR7JwQUYTgE4SAt1n7EwBaMCVV
   5.118 +16vo5O2r1/z9G2vkn4vbydF/44XFEcC0mlWOPtVhQ39MnlAjx8wgWkf/8pIYu+Ne
   5.119 +JIrdidMe0ecAQV/z9eQw0C4Wag/Sjp0llPHOiwOSGtOJ811xc9nlSKNoIJvCPU6X
   5.120 +CI1x1ue91xNyPA1i0K/VwyRnYzDm2BEVQTYymoHVf0qi+g/Hs5xgU+unNAJivbbL
   5.121 +xH6ZH+TzLtMfFmL6oWRrPz/6c+1Dn9OtMd9iwsK4BBgBCgA2Ah4DApsCBYkFn6YA
   5.122 +AhUKBYJc1Bg1FiEEq8lrO0uvtX3EXYG1akgiGpA6FYsJEGpIIhqQOhWLAbbA9KAE
   5.123 +GQEKACcFglzUGDUWIQQz8QOZ/vi9W3qvpZTc1VW2BVreIgkQ3NVVtgVa3iIAAMck
   5.124 +C/9Enlxfu0GqWcOdYKxC6xoNoFhFrCrTRAwGfS8h8Q17y6gelstSw+x6Lh5PYOHe
   5.125 +/hkf1U6nKkTcgZeKuoiU/JDkje+G2UDxzc0IDl3bXp9HSoplvSdlmAKGTFORyKg7
   5.126 +bhScBzpYbmdGxfmCxBnbFYdSU374MuyXyaYePExW7m1kKjWFQvgwGbTRj+/B342/
   5.127 +uhx7Ixl2GgXPvhFT/qkVUf7X/iUIvtT73xj0rVVL9Ox+KjgLbuG1dYzg2blptXbw
   5.128 +O8ttg+SXrycoVR23IgMcll5vnqEn0iB33TCLxqRxOwa1Bg/TyBaZX0qK3CjmNIvW
   5.129 +QLJ554HC3xKJsPnDg9kA9FDYO/Z1aoUm5TST82KlOXQQ8aaT5zFWms67x3C1WX2+
   5.130 +6kJ+Ox+3N15IOZE7ziMxj+taKxtdGM5s/GWs8hlWydvidz7TUi/r7OgLtT/M1t2b
   5.131 +iQQj9wVSE1b4T1mC+zGVpVf9EC0PJDkedMG4AW2UhsLY88ShkVA1J1uTlSsKPsQQ
   5.132 +O3escwv+JeoBB1Hox4STOE17XyjaSG394DeiMaxdizjGtMBuQPxyeGt95IQV9wit
   5.133 +C2qVOrfB8RjFMLC30vKrS85tynYp+ibqOa3387YvvRujlbV1FMnRFs1iUGLTwftb
   5.134 +M0L6ndqq2T5F16j40QWOtgXU5LKa1wvAOIHQ5ZhtNoMggxP+YYjoQjimrFUfPTOW
   5.135 +Ot+dffoSQgK3elDNbzK7PziSGg/WwCmYrJOTVu5purJWw80rfiaBrpgiJLAU+jpQ
   5.136 +BC9HkznSBxAGdTNaqOGrifwIBMqBZt9eC+sDex6f7j1Kyn1y4uExy5Sk86D8N2eV
   5.137 +LobkSc7ri9rTsjp9xYq3eauKunnNqz8qU63LKt2CBFf4/y2fdBrGXV+GuSNeYDHy
   5.138 +c4fFeUdBI8/gRq1irgU4BGoMqG/RgxroKc5ggvOj5Wbd0e146ksSQDia3/a1s1hL
   5.139 +rnqRKdw5qN5peyUmOgZWW4w1NMbT0oRdtznVurwKvtRdd2WBzE6IPkEkJXO1muVF
   5.140 +iNlLnPZz
   5.141 +=i7QC
   5.142 +-----END PGP PRIVATE KEY BLOCK-----