sequoia-policy-config-0.8.1/.cargo/config.toml000064400000000000000000000004451046102023000173560ustar 00000000000000[resolver] incompatible-rust-versions = "fallback" [target.'cfg(all())'] # Note: if the RUSTFLAGS environment variable is set, this will be # ignored. rustflags = [ "-Aunused-parens", "-Aclippy::all", "-Dclippy::correctness", "-Dclippy::suspicious", ] sequoia-policy-config-0.8.1/.cargo_vcs_info.json0000644000000001360000000000100152500ustar { "git": { "sha1": "91d6436052d1a809b8e91719f3f9df122c1dbb07" }, "path_in_vcs": "" }sequoia-policy-config-0.8.1/.ci/all_commits.sh000075500000000000000000000022711046102023000173550ustar 00000000000000#!/usr/bin/env bash # Test all commits on this branch but the last one. # # Used in the all_commits ci job to ensure all commits build # and tests pass at least for the sequoia-openpgp crate. # NOTE: under gitlab's Settings, "CI/CD", General Pipelines ensure # that the "git shallow clone" setting is set to 0. Otherwise other # branch are not fetched. set -e set -x # Use dummy identity to make git rebase happy. git config user.name "C.I. McTestface" git config user.email "ci.mctestface@example.com" # Make sure the gitlab project is configured. if ! git describe --all origin/main then echo "origin/main is not present. Configure the gitlab project (see .ci/all_commits.sh)." exit 1 fi # If the previous commit already is on main we're done. git merge-base --is-ancestor HEAD~ origin/main && echo "All commits tested already" && exit 0 # Leave out the last commit - it has already been checked. git checkout HEAD~ git status git rebase origin/main \ --exec 'echo ===; echo ===; echo ===; git log -n 1;' \ --exec 'cargo test --all' && echo "All commits passed tests" && exit 0 # The rebase failed - probably because a test failed. git rebase --abort; exit 1 sequoia-policy-config-0.8.1/.codespellrc000064400000000000000000000004031046102023000163350ustar 00000000000000[codespell] skip = *.bin,*.gpg,*.pgp,./.git,data,highlight.js,*/target,Makefile,*.html,*/cargo,*.xml,*.xmlv2, ignore-words-list = crate,ede,iff,mut,nd,te,uint,KeyServer,keyserver,Keyserver,keyservers,Keyservers,keypair,keypairs,KeyPair,fpr,dedup,ba,captable, sequoia-policy-config-0.8.1/.gitignore000064400000000000000000000000101046102023000160170ustar 00000000000000/target sequoia-policy-config-0.8.1/.gitlab-ci.yml000064400000000000000000000001731046102023000164750ustar 00000000000000stages: - pre-check - build - test include: - component: "gitlab.com/sequoia-pgp/common-ci/sequoia-pipeline@main" sequoia-policy-config-0.8.1/Cargo.lock0000644000001346260000000000100132370ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", "generic-array", ] [[package]] name = "aes" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", ] [[package]] name = "aes-gcm" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", "cipher", "ctr", "ghash", "subtle", ] [[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "argon2" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", "blake2", "cpufeatures", "password-hash", ] [[package]] name = "ascii-canvas" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" dependencies = [ "term", ] [[package]] name = "assert_cmd" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcbb6924530aa9e0432442af08bbcafdad182db80d2e560da42a6d442535bf85" dependencies = [ "anstyle", "bstr", "libc", "predicates", "predicates-core", "predicates-tree", "wait-timeout", ] [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bindgen" version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ "bitflags", "cexpr", "clang-sys", "itertools 0.13.0", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", ] [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "blake2" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ "digest", ] [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "block-padding" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ "generic-array", ] [[package]] name = "bstr" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", "serde", ] [[package]] name = "buffered-reader" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db26bf1f092fd5e05b5ab3be2f290915aeb6f3f20c4e9f86ce0f07f336c2412f" dependencies = [ "libc", ] [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ "find-msvc-tools", "shlex", ] [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-link", ] [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", "zeroize", ] [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "cmac" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" dependencies = [ "cipher", "dbl", "digest", ] [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crunchy" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core", "typenum", ] [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] [[package]] name = "curve25519-dalek" version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest", "fiat-crypto", "rustc_version", "subtle", "zeroize", ] [[package]] name = "curve25519-dalek-derive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "dbl" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" dependencies = [ "generic-array", ] [[package]] name = "der" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", "zeroize", ] [[package]] name = "difflib" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "const-oid", "crypto-common", "subtle", ] [[package]] name = "dirs-next" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ "cfg-if", "dirs-sys-next", ] [[package]] name = "dirs-sys-next" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "doc-comment" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" [[package]] name = "dyn-clone" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "eax" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" dependencies = [ "aead", "cipher", "cmac", "ctr", "subtle", ] [[package]] name = "ed25519" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", "rand_core", "serde", "sha2", "subtle", "zeroize", ] [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "ena" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", ] [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fiat-crypto" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "fixedbitset" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "generic-array" version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", ] [[package]] name = "getrandom" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", "wasip2", ] [[package]] name = "ghash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", ] [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "hkdf" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ "digest", ] [[package]] name = "iana-time-zone" version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "log", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", "writeable", "yoke", "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "indexmap" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "inout" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", "generic-array", ] [[package]] name = "itertools" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "js-sys" version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "lalrpop" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", "ena", "itertools 0.11.0", "lalrpop-util", "petgraph", "regex", "regex-syntax", "string_cache", "term", "tiny-keccak", "unicode-xid", "walkdir", ] [[package]] name = "lalrpop-util" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ "regex-automata", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ "spin", ] [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libloading" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", "windows-link", ] [[package]] name = "libm" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags", "libc", ] [[package]] name = "linux-raw-sys" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ "scopeguard", ] [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memsec" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nettle" version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44e6ff4a94e5d34a1fd5abbd39418074646e2fa51b257198701330f22fcd6936" dependencies = [ "getrandom 0.2.16", "libc", "nettle-sys", "thiserror", "typenum", ] [[package]] name = "nettle-sys" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a3f5406064d310d59b1a219d3c5c9a49caf4047b6496032e3f930876488c34" dependencies = [ "bindgen", "cc", "libc", "pkg-config", "tempfile", "vcpkg", ] [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "num-bigint-dig" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b" dependencies = [ "lazy_static", "libm", "num-integer", "num-iter", "num-traits", "smallvec", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-iter" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "ocb3" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" dependencies = [ "aead", "cipher", "ctr", "subtle", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "parking_lot" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-link", ] [[package]] name = "password-hash" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core", "subtle", ] [[package]] name = "petgraph" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", ] [[package]] name = "phf_shared" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pkcs8" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", ] [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polyval" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", "opaque-debug", "universal-hash", ] [[package]] name = "potential_utf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] [[package]] name = "precomputed-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "difflib", "predicates-core", ] [[package]] name = "predicates-core" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quickcheck" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ "rand", ] [[package]] name = "quote" version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.16", ] [[package]] name = "redox_syscall" version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.16", "libredox", "thiserror", ] [[package]] name = "regex" version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "sequoia-openpgp" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0e334ce3ec5b9b47d86a80563b3ecec435f59acf37e86058b3b686a42c5a2ba" dependencies = [ "aes-gcm", "anyhow", "argon2", "base64", "buffered-reader", "chrono", "cipher", "dyn-clone", "eax", "ed25519", "ed25519-dalek", "getrandom 0.2.16", "hkdf", "idna", "lalrpop", "lalrpop-util", "libc", "memsec", "nettle", "num-bigint-dig", "ocb3", "rand_core", "regex", "regex-syntax", "sha1collisiondetection", "sha2", "thiserror", "win-crypto-ng", "winapi", "xxhash-rust", ] [[package]] name = "sequoia-policy-config" version = "0.8.1" dependencies = [ "anyhow", "assert_cmd", "chrono", "quickcheck", "sequoia-openpgp", "serde", "thiserror", "toml", ] [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "sha1collisiondetection" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f606421e4a6012877e893c399822a4ed4b089164c5969424e1b9d1e66e6964b" dependencies = [ "digest", "generic-array", ] [[package]] name = "sha2" version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "rand_core", ] [[package]] name = "siphasher" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spki" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", ] [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "string_cache" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", "parking_lot", "phf_shared", "precomputed-hash", ] [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tempfile" version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.4", "once_cell", "rustix", "windows-sys", ] [[package]] name = "term" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ "dirs-next", "rustversion", "winapi", ] [[package]] name = "termtree" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tiny-keccak" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ "crunchy", ] [[package]] name = "tinystr" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "toml" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", "subtle", ] [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ "bumpalo", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "win-crypto-ng" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99abfb435a71e54ab2971d8d8c32f1a7e006cdbf527f71743b1d45b93517bb92" dependencies = [ "cipher", "doc-comment", "rand_core", "winapi", "zeroize", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-interface" version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xxhash-rust" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "yoke" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] sequoia-policy-config-0.8.1/Cargo.toml0000644000000037630000000000100132570ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.85" name = "sequoia-policy-config" version = "0.8.1" authors = ["Neal H. Walfield "] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Configure Sequoia using a configuration file." homepage = "https://sequoia-pgp.org/" readme = "README.md" keywords = [ "cryptography", "openpgp", ] license = "LGPL-2.0-or-later" repository = "https://gitlab.com/sequoia-pgp/sequoia-policy-config" [package.metadata.docs.rs] features = ["sequoia-openpgp/default"] [badges.maintenance] status = "actively-developed" [lib] name = "sequoia_policy_config" path = "src/lib.rs" [[bin]] name = "sequoia-policy-config-check" path = "src/check.rs" [[test]] name = "check" path = "tests/check.rs" [dependencies.anyhow] version = "1.0.18" [dependencies.chrono] version = "0.4" [dependencies.sequoia-openpgp] version = "2.1" default-features = false [dependencies.serde] version = "1.0" [dependencies.thiserror] version = "1.0.2" [dependencies.toml] version = "0.5" [dev-dependencies.assert_cmd] version = "2" [dev-dependencies.quickcheck] version = "1" default-features = false [target."cfg(not(windows))".dev-dependencies.sequoia-openpgp] version = "2" features = [ "crypto-nettle", "__implicit-crypto-backend-for-tests", ] default-features = false [target."cfg(windows)".dev-dependencies.sequoia-openpgp] version = "2" features = [ "crypto-cng", "__implicit-crypto-backend-for-tests", ] default-features = false sequoia-policy-config-0.8.1/Cargo.toml.orig000064400000000000000000000026171046102023000167350ustar 00000000000000[package] name = "sequoia-policy-config" authors = ["Neal H. Walfield "] homepage = "https://sequoia-pgp.org/" repository = "https://gitlab.com/sequoia-pgp/sequoia-policy-config" readme = "README.md" keywords = ["cryptography", "openpgp" ] description = "Configure Sequoia using a configuration file." license = "LGPL-2.0-or-later" version = "0.8.1" edition = "2021" rust-version = "1.85" build = "build.rs" [badges] maintenance = { status = "actively-developed" } [lib] name = "sequoia_policy_config" path = "src/lib.rs" [[bin]] name = "sequoia-policy-config-check" path = "src/check.rs" [dependencies] anyhow = "1.0.18" chrono = "0.4" sequoia-openpgp = { version = "2.1", default-features = false } serde = "1.0" thiserror = "1.0.2" toml = "0.5" [dev-dependencies] assert_cmd = "2" quickcheck = { version = "1", default-features = false } [target.'cfg(not(windows))'.dev-dependencies] # Enables a crypto backend for the tests: sequoia-openpgp = { version = "2", default-features = false, features = ["crypto-nettle", "__implicit-crypto-backend-for-tests"] } [target.'cfg(windows)'.dev-dependencies] # Enables a crypto backend for the tests: sequoia-openpgp = { version = "2", default-features = false, features = ["crypto-cng", "__implicit-crypto-backend-for-tests"] } [package.metadata.docs.rs] # Enables a crypto backend for the docs.rs generation: features = ["sequoia-openpgp/default"] sequoia-policy-config-0.8.1/LICENSE.txt000064400000000000000000000627341046102023000156770ustar 00000000000000Sequoia PGP is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Sequoia PGP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --- GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! sequoia-policy-config-0.8.1/README.md000064400000000000000000000044521046102023000153240ustar 00000000000000A library for reading the configuration of [Sequoia]'s `StandardPolicy` from a configuration file. [Sequoia]: https://sequoia-pgp.org [`StandardPolicy`]: https://docs.rs/sequoia-openpgp/1.11.0/sequoia_openpgp/policy/struct.StandardPolicy.html Sequoia's [`StandardPolicy`] can be configured using Rust. As with most things, Sequoia's low-level library avoids imposing a policy on users of the library, like where a configuration file should be or even what format it should have. When necessary, it is up to the application to provide an interface, and to configure the policy appropriately. This library provides a high-level interface that parses a configuration file, and returns a configured `StandardPolicy`. See the crate's documentation for a description of the file format. ## Quick Start To add `sequoia-policy-config` to your crate add the following your crate: ```toml [dependencies] sequoia-openpgp = { version = "1" } sequoia-policy-config = { version = "0.6" } ``` This will use `sequoia-openpgp`'s default cryptographic backend, which is currently Nettle. To select a different cryptographic backend, such as OpenSSL, you can then do: ```shell cargo build --release --no-default-features --features sequoia-openpgp/crypto-openssl ``` To use `sequoia-policy-config` in your crate, it is usually enough to replace the use of `StandardPolicy::new` with the following:: ```rust use sequoia_policy_config::ConfiguredStandardPolicy; fn main() -> openpgp::Result<()> { let mut p = ConfiguredStandardPolicy::new(); p.from_bytes(b"[hash_algorithms] sha1.collision_resistance = \"never\"")?; let p = &p.build(); // ... Ok(()) } ``` ## Building This crate is purely a library, so it is not usually built directly. If you do build it (e.g., because you are modifying it), you'll need to select a cryptographic backend. See [`sequoia-openpgp`'s README] for details. [`sequoia-openpgp`'s README]: https://gitlab.com/sequoia-pgp/sequoia#features The short version is: ``` # Use the Nettle backend: $ cargo build --release --features sequoia-openpgp/crypto-nettle $ cargo test --release --features sequoia-openpgp/crypto-nettle # Use the OpenSSL backend: $ cargo build --release --features sequoia-openpgp/crypto-openssl $ cargo test --release --features sequoia-openpgp/crypto-openssl ``` sequoia-policy-config-0.8.1/build.rs000064400000000000000000000023171046102023000155100ustar 00000000000000use std::env; use std::fs; use std::io; use std::io::Write; use std::path::PathBuf; /// Builds the index of the test data for use with the `::testdata` /// module. fn include_test_data() -> io::Result<()> { let cwd = env::current_dir()?; let mut sink = fs::File::create( PathBuf::from(env::var_os("OUT_DIR").unwrap()) .join("tests.index.rs.inc")).unwrap(); writeln!(&mut sink, "{{")?; let mut dirs = vec![PathBuf::from("tests/data")]; while let Some(dir) = dirs.pop() { println!("rerun-if-changed={}", dir.to_str().unwrap()); for entry in fs::read_dir(dir).unwrap() { let entry = entry?; let path = entry.path(); if path.is_file() { writeln!( &mut sink, " add!({:?}, {:?});", path.components().skip(2) .map(|c| c.as_os_str().to_str().expect("valid UTF-8")) .collect::>().join("/"), cwd.join(path))?; } else if path.is_dir() { dirs.push(path.clone()); } } } writeln!(&mut sink, "}}")?; Ok(()) } fn main() { include_test_data().unwrap(); } sequoia-policy-config-0.8.1/doc/release-checklist.md000064400000000000000000000031571046102023000205240ustar 00000000000000This is a checklist for doing releases. 1. Start from `origin/main`, create a branch `staging`. 1. Switch to the branch. 1. Bump the version in `Cargo.toml` to `XXX`. 1. Bump the version in `README.md` to `XXX`. 1. Run `cargo check` (this implicitly updates `Cargo.lock`). 1. Update dependencies and run tests. - Use the exact Rust toolchain version of the current Sequoia MSRV (refer to `Cargo.toml`): `rustup default 1.xx` - Run `cargo update` to update the dependencies. If some dependency is updated and breaks due to our MSRV, find a good version of that dependency and select it using e.g. `cargo update -p backtrace --precise -3.46`. - Run `cargo build && cargo check` 1. Commit changes to `Cargo.toml` and `Cargo.lock`. 1. Make a commit with the message `Release XXX.`. - Push to gitlab, and create a merge request. Don't auto merge!!! 1. Make sure `cargo publish` works: - `mkdir -p /tmp/sequoia-staging` - `cd /tmp/sequoia-staging` - `git clone git@gitlab.com:sequoia-pgp/sequoia-policy-config.git` - `cd sequoia-policy-config` - `git checkout origin/staging` - `cargo publish --features sequoia-openpgp/crypto-nettle --dry-run` 1. Wait until CI and `cargo publish ... --dry-run` are successful. In case of errors, correct them, and restart. 1. Merge the merge request. 1. Run `cargo publish --features sequoia-openpgp/crypto-nettle`. 1. Make a tag `vXXX` with the message `Release XXX.` signed with an offline-key, which has been certified by our `openpgp-ca@sequoia-pgp.org` key. 1. Push the signed tag `vXXX`. sequoia-policy-config-0.8.1/openpgp-policy.toml000064400000000000000000003334151046102023000177130ustar 00000000000000version = 0 commit_goodlist = [] [authorization."Justus Winter (Code Signing Key) "] sign_commit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: D2F2 C5D4 5BE9 FDE6 A4EE 0AAF 3185 5247 6038 31FD Comment: Justus Winter (Code Signing Key) "] sign_commit = true sign_tag = true sign_archive = true add_user = true retire_user = true audit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: CBCD 8F03 0588 653E EDD7 E265 9B7D D433 F254 904A Comment: Comment: Justus Winter Comment: Justus Winter Comment: Justus Winter Comment: Justus Winter Comment: Justus Winter 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 GNLnNS2c13ota/HZo1jjyOOIhJ3wkyUY5s8ugtxIwO4gE34rgdxXe1w7w2dy3DKq zWOHKs7wca8m6ufk75MQGk7TPL6nXZM+1F6OBo+moEaW/X8hn4meXikLE/6p4PxG wclL3/+FbwlJpMjPunedyDa+CVL5yCf7vww8mW52YiIWHNvmSJ5szWgc276uMk0T 1+ckzQ1KdXN0dXMgV2ludGVywsHhBBMBCgCZBYJofiMXBYkQ8B+PAwsJBwkQm33U M/JUkEpHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jndceh oMOXCdcGEK5NieaTCfHICdd30Ek4k7Ypxe002Z0FFQoOCAwCFgACF4ACGwECHgkW IQTLzY8DBYhlPu3X4mWbfdQz8lSQSg0nCQIJAQkDBwIHAQcDAABY9g/gnj/02oHg NDdYg7P3fWZAkABu8Gj0uH68dpFCIL8wCc5AL9l6WVSBmdxFmoNMD7TsKfiBRVg1 9IUWitxb0bcmm/OzzkvGgk1SG8gcJE46oA4sumfNh/7CnHUAvKL4ALIPMMXUDkz3 KhmUaqnZdzpQYsGRvujgOaKCia0xVNCSh2t1wGPPyIP0QLCrC6Ntcm/HD0tEQlU7 0GxLMNAzsD6ag4iqZI8X1/qilbbtiIYdoiT+bU9CWuv/fBx/nK43O4+t/G168vfh mseTAhI/q8ObbrQJB9aJJW7gbF2Qs2wC6yrtb8BYaKpfSzNXAlKH+YQbFdouq8m1 NPNoUbU27dMEG9KPeQXAiv74N4upkNpUju1IieJ80fat4QWx3pstlbCU2dfS7/8n FqbW74QFjy6eR/Mt81exw1+rxW4CMRVLnGeTxvMYWVJvj34F/dHOjGk/CNkeMvDK T+PggTHT1O/54wEgdURUKD9L0VOaBlVFIawmqfmKdXd3qks2mtakPv29vR6CnKPQ M59DSU3hE7XjWXndgjjT70d2GYcDEybBB37sy6h4dh0kc8+BWTwJztMDn2ffhUD7 XwKlTpFBhHwPcS3q+SbDApKxrOhYoSmdzez92lwG7748Cu/WZIB2u65kvzm+l4ov vuUuGcyOf7rSalLjGz+J4n7IywWz/cLB4QQTAQoAmQWCZ9gwBgWJDwBWzQMLCQcJ EJt91DPyVJBKRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y 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 tHKhU4JgfYfj3/ZkxE7B8rTAgDZ/l7ax+ppDmWU17OqhIVx7RFBxLEEg90569zT4 cvYROmoHhr7CweEEEwEKAJkFgmfYMAoFiQ8AVs0DCwkHCRCbfdQz8lSQSkcUAAAA AAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmdVuzGVhHnLLB+JWAgd MQStKDJtRcLwGgcPL1i8xDel+QUVCg4IDAIWAAIXgAIbAQIeCRYhBMvNjwMFiGU+ 7dfiZZt91DPyVJBKDScJAgkBCQMHAgcBBwMAANgKD90amXbCcheJIIlYxu6w+CI8 u+fBK5wzvAsBus+lPiiHIMwwcOiWM5cSY1zHWmrHT7UvIJ64TEJbyyIYtvy5/LPV O0b+m95MeVHWTEyqY0TylIqyjKBJeQdUmZiJERWXOCOhqOCxT+VSZ15k3KYP/jIH byldOvjpsWRcTwaJq2lvTPBUbJ9hzPNkuTdIFrmqPMJypgfBm+HwsIbH1XAEUKEq GpofsAh5NSGDZVWOT8ZHtpHiA8fAN1iTsM8hjd6EQ9UzR2BuRv964e+5cVFLmSnU kCHxUM1vyjciFq6pv6Zxhzdb8DEBvcABBwtyihFvKdNd8sKUyjKvB7Fo3Qaz/8xC dEJSHdqCJGJCO1DWHP3L+L59D4g2MKu3YAlOQDx2izEafJfRVQhwYLvlswzaeV93 aaM5gNEHRIayHaOOOR2xcZR27Vc/iL7z6vHUSw8GTUcQjm9uA5VWegR1dHIDC4ok is43nNBinP1lp1o4jNe5cQSpOalRrgprr8ow7YuEe07MmqvC1q6udYGNf3YZVgfW KiBWSU2N0JEVCCjD4Ae2+0d6qph6BWwjbKQtTQ8Rv5OMFJtlKKHVMXLBYfkI2gMy YPgTT0Vc0D3wqrqeSHPxwGIeWF83e5dMIE3Wnme9NOChQkFCWAH40YMhNutrG3dR AJM8WExkMyAL0gmzwsGNBBMBCgA7AhsBCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEE y82PAwWIZT7t1+Jlm33UM/JUkEoFAmaOrBwFCQ8AVs0ACgkQm33UM/JUkEr2rA/g sXbm0JtEbE/gzxoLlI71WhZFvXWwZehWpNnxWuBgnxHyCAiB6Ulf0wqlfTyRUirI o6pcL9Gadj6y4V5sxa8NLH6Zvv2KeLelNjMTSx3VPAbSprhzLQXvO25wubmfI8wP 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 wocIA3yDQ/POwE0EWW+JnwEIALljGLPt+4QNsRcqLgzAVXsgTpDeYQmtdZh3otmM vMU76/cM+Ez9iBA50jvD7x5imuwVpQ+1gAsXLhtH/lQUaP0zTRGTe2CVXd0LTlCI cbNpEaAbVbTgfmFxC4bUOJNcyuABfOVklTBceRplK0iWRs1zXf/K8Qrz/Ujv7W5p w+WckeFKH30Pg8wlMt/yLZZTHTsxUhGh4gP35oXvfmFxb2si7obPUfSywmSzVk/U 8WVhx7IMJPMb9iJnPCIB/AecM+mUC8rIyhjHQsZB22/5akyiGFpJ10ve92MOKrzU fessmj4YK1rjY1wDSsMFf9bPt4sNZ8o96ajZWma+zMn9lhcAEQEAAcLC9gQYAQoA eAWCaH4jlwWJEPAfNwkQm33UM/JUkEpHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu c2VxdW9pYS1wZ3Aub3Jnw2NNWQrZUBaUYYLV8LDmEeEG76wn6pJcMlxZVZw5Y7oC GwIWIQTLzY8DBYhlPu3X4mWbfdQz8lSQSgE2wHQgBBkBCgAdFiEEJWpOVeSnLZet JGjniNx+MzhfeR0FAllviZ8ACgkQiNx+MzhfeR3XZgf/ViFPa4G4HdY7X9GrinjD /GYvQnHeQl/NsY4lIEzR5/8GptxbeMTF0kjGGX6snU+oCshPSUibcd09eBIWZ+B1 KJcUosvxvvEIuegA+t8Yb61QWzj+GDzc8az/+atr8fM4a6Y6Y3KQojCCy2+ouZ9D LZRHLNHpZx5uwBN6/zzr+CuNCkLIY5XWZYIKPaoscRCuXqxEYCkO9zZFvvHSZatt s8sBZJkpgVlT7GdGwpqw55phJGZi/qSFXi3U52BCli5t/r4jJ2KfpO/lnCkfupSQ 5nIJA8+TlsOksz0DY3Mlti9PtLV9YbgNkOO2eSOcl3mmrgJXy2jh+0qOGG28WpkE AJSnD+CKo2jppMFmS0YmIT6UVVsoYvWnUmDJ5SCSnJR/GMBwSfKD/SfWxQAPLWzn 5onVRlyFCpBEaEqj3xb6d8Dr/3K0EZ6kdF89SW4spO/a3VDlfAJQ5oYNtlg+FW+k hUb6q4sEYp1tNUGfWwqDCjuSugqLfgpqZaO1nq55bMl3nEL3BndDp97GrSZx6I/P Cfzmwsuny/61tjCAY+NQBGAtc8zgiEM1xoIDJgBF27DDFRPpR9pwQLjlKro0AVhW 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 =N5EW -----END PGP PUBLIC KEY BLOCK----- """ [authorization."Neal H. Walfield "] sign_commit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: F717 3B3C 7C68 5CD9 ECC4 191B 74E4 45BA 0E15 C957 Comment: Neal H. Walfield (Code Signing Key) "] sign_commit = true sign_tag = true sign_archive = true add_user = true retire_user = true audit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: 8F17 7771 18A3 3DDA 9BA4 8E62 AACB 3243 6300 52D9 Comment: Neal H. Walfield Comment: Neal H. Walfield Comment: Neal H. Walfield Comment: Neal H. Walfield Comment: Neal H. Walfield xsEhBFUjmukBDqCpmVI7Ve+2xTFSTG+mXMFHml63/Yai2nqxBk9gBfQfRFIjMt74 whGG3LA1ccH2vtsUMbm+F9d+hmzfiErloOVeamfSTCXVPHl4vuVRGXoH5tL09bbm LE7cidDj49GelOxbfqHKVw3+Fd2zLlQdiaWYJ7CdRDZOT22zEx+6n59/gO5WNnym aib+nXWAbXJ+pU7fzHU4PlhDXT/FfV2mzyQg6AiToColG5/CfOBp+WP6pAU4eNIx IlKYxzLnyAPUy+nuqojTJ+Ni16Jve/hpKM7G1TGAzjzdC5zSVMELi/5kdldCD9Hg 7sqw6RPlxbH52bryenYfLyfIaInHCHKmqWRAu3fxMcZ65qo8khYrzZngYewVAafR i/GSZmKxzntmP0GYziceGsbF8dEFF1scfebGKuDqtBhQ0MMuxTbTLg1+KKN8rhqW Teikrt0JPbD1viaVX7Z7G12fZ8lBU4sjd3HGO5EK+3Cs8bjLXbzb8UIz7u28u7Dq VQB4jhgh+IXyZzaeELV9KPr5IVNjT9K9gX6JJlVSi5BnxUVY0pEhtKiiLO6PCC2N PenWkWpp3UEZ5ILnLhlmPe7ICiBCK1IQtNHEAfDalKO1t/gWKi0JlOqv2j9ER68A EQEAAc0jTmVhbCBILiBXYWxmaWVsZCA8bmVhbEBnMTBjb2RlLmNvbT7CwUoEMAEK ACAWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCWc01BwIdIAAKCRCqyzJDYwBS2R08 DqCVcQ7mbbsFgEX/0SpcrWIYznMFqrRwIYuYysJxmhUYTHqV1FJiECjVBPOLabov /DSHlCHi2GrpImI4ReKgLDdYAMlAL5zca21lDHGwtghYAXkWMqyQa2SIL5+6+cNB A1tlEPcVAknLqg7At92VHOQMBKaQLR46Dt0BowhnrKbPC/ICnquO7g5nhXMfwN0+ tA+3QDp6nbAjEXDF94zKgG1PXgHTgB3F3oMUipJo5xMfzXJZ0EgsDJiXRjRAu7Lp 44nv6eKJdUw1mVKmo+BfbChC99LuqSNQornEinXUVv/ecjIuWqK10w18BLFFZCnX S+WsPFWSQ4Bl0LIfA+g/TACBsq8gBybkxm0GE/YQw1oSP9VLPEQUaJspeIp1jIW6 wEOLIbPB3KWj/RGvZddDhXz5y1rSOUhg3ObAcC9ytWmpAHr4Q/4onOThL3e7VFNi SK7rEX19TD2dGLMfOiD+lsDrbcmYQL+1bzpQPjO1WlzA8/rBMe/EDjWTV9p7xiC2 Y/BIbph6WgaFX+9VioJ5CIbFssOfkl9VOOStdhsG55+cbv+1xkJ5kUEKm9sjpDO/ GUK9+kI6Yge2I9W3+DeT1PAzwyu0Cj2ePRYEJkp703KXggNfiIjCwWUEEwEKACQF AlUjpZACGwMFCRLMAwAICwkIBw0MCwoFFQoJCAsCHgECF4AAIQkQqssyQ2MAUtkW IQSPF3dxGKM92pukjmKqyzJDYwBS2RZGDpsEbOO6HrU2F5SK4Kc03ndtXi0jpCci Z+nDjfm6TOEBDbYx5YUOsYwnfXt7aWSSNikRTyEZHWA3BExE2J7ddNG8OGIhAnAH +USj4cTmEwlwTdAMyXSVL1Hp82Vsr9CcdJNU6jAxi0QDJk9d8EvDksbQUy8fuDbs dgKb16QjL2nsEZ2Gd7fKluK3I8pTU81cbEA7s/4d3sQzGCLomHQ+75436gypcglN q84TWtpeMAUYku7pl8Do1oj8lryQBqnjKJTRXic3gtN4f7YoRkrCIcRXbeCCdc2k bQbcp8CEjI/NPNTezyXn8Sk6RsJitf+L5Op3yPmcagay2ycjRdfMdPA6V4VC+e8H MAFzSWigdBPrCP6e/7Wo94sMy4lrQtjxHaY7uAqk025KrXMti9KvK5yL0xzww1yh WAHEB6Oso2DS3/FRBAKhn+n7gp8HwjyDAieXP1leL1RToO2a0jJ+MNfWOmWRnGbr U5op9nLaseW4PopTO9G4m+gSJxuTgxiP7Ovo/eD8dicaoEtgvLEi0mSGpZUgdZXd pB8Eo/wiD6wFD1NkMRWYRSlS0b3ataC91z0DmPpoEZ+5F36ZzPgLmvxqN/FCFwb0 bMmDyHo5pAH+niuAi1rNIU5lYWwgSC4gV2FsZmllbGQgPG5lYWxAZ251cGcub3Jn PsLBZQQTAQoAOwIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgBYhBI8Xd3EYoz3am6SO YqrLMkNjAFLZBQJoPu+wBQkU/IguAAoJEKrLMkNjAFLZwg0On0fD2wlUllFPdsRf auqi2e23/JdQIQ0VQNA/r92xXEbfpxO9D03FqzQI0wLgCSJs0yxOC8rmOdCcMnLd 6iwAFb/YJLpDi9BLEfsAJ+0g2oQMMbuSrUPqm7kXEEVhiffLlEl/1PEE5jSGFa1D KTciFL7admDuUjdwXJ5Kat9thQXhO8HZ3SoBoLqodCFT2sC7pmRJj7TOGSOIDtY5 lvd7ESece7eQxp1ow3HiUaLjHGBWYLdpTNzQ8Y7Kw5kY0APeSwgDO85z8ZzceQWS 33Mxb8Um4UZ+0vlIlnPR48D4H5HYuGjUj2qOWo3uyvyBTisfT+TYSrtIb+kalKfr vpXyiRSq8lQorTWc1ikWQvX3rh+mqACbL8l8BCK1Id3CzkE0mAEKiQFPUXU8GkJu 9JjiwUyjqhhOd1yqfvNc5rOx+qe3r+wdYP8FLVny2HtoSRFnSxgs1entWp3FI196 p84tidugy5KkZ6HosH5dickEV1labKKoIwtX/IpFPdR4pUBlzVYH0OojWYCNAXBt d8pFpe0NTkaN1GMSBZhp/Iwo0vPFOaQT/QyU7sNaimZz9OwPb2dvEQ6Llo+RVY5t TUtGZUIEFW7V2yjVLHzhuns4vjERhmHzCcLBZQQTAQoAOwIbAwgLCQgHDQwLCgUV CgkICwIeAQIXgBYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJmzCnUBQkTDIO7AAoJ EKrLMkNjAFLZErAOn0fLiphDTNzyRbZeSRL96PjRNU/RfnpWRF4OucqUY5SfwVg1 MaEUi3N079l33YGQjo1X/ylgc55DRQcw1o+sQEEfjn9vjqV6fjm2xY8rNUMd4/Cg WfLik7tOwF/Mb4tdNubFeEAPIMz8UKhBedq0oHqW/EhaAhoST82PGRl+TDqcbMQ7 ZwhEHjok5tbY5bOZYpHOkaj/HuJg9ZzZS7YJgPksjFctm9aHN5406M+N9Cxz5MP0 Ci/uQmam2je+/nIH9Q3ASmtNKEKxsPzm3FdDUt4Ogmuvf/42kExJFtQSmPDFCUEt M4IW3ShzUOfkIeS/hamWcNm7AT7VgOnccp/HkddROX5Fz10vc5gqzbW18pU99BF1 2URLm/O7RCqMfKgp66BCuTpj8Y+fJ9bkIBp/zHdzpV5FytAtpTiygODcVUdUH8SS 3ip3fM2ozbNXf0V/KdXvtrh1Ug1Rp5fwEYMan705XZetOO8HmcST3hQL/xivWBHa 4zdS6tMy+wzxgynmBP/ievURbwHCHduEWm3DDuInuRa8sL5gg6+lHxh7FahJsd4V unl7N96w25Jv/u46Dpkiar8mTnwszuzfY5cL519ttjpPF7Yw55fFOqdauS6e18c/ EcLBZQQTAQoAOwIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgBYhBI8Xd3EYoz3am6SO YqrLMkNjAFLZBQJl3aSvBQkRp1e1AAoJEKrLMkNjAFLZMocOmgPUi5hvcTR/7a/F 2vXpiJAPW20qWBMJHmEJTgSaFL2wPlAY/1LbrwyLyWsY2MjmOnOjVR00cvLHz8bV 9kncRUqLp+ERqO+GVe5pPT0jAaNI7F4zcmKyh9lEAy+kqOtEZAcVnmJDjqVYyfmw 53m8lGCcbFgEYHVwtJR+/xDq6KTZjRAuzPuKzF5Ztl/9n7I8513UV0XO/EPekMw4 CNew4IE0n08nQVAiGknag4CHQMzSosXpetrzk3LhRjZiOgsmEU3aLe6dOFY/Bips U1iq+/gF8Dv2UQliR85+SN4Y0M9G8V1qpO3yWvfDwdSYHhK0uMpO6JfKvVWi/fju ZOjuVOrrhdBfscPxSGJrWpfRwgFGNrvSANYh53AsLr9Q+KlpTqpiy1xYN+Qsy/6q JfyPnEfAJOCMXTJBZzOR90qi4CsSGhyTNRBXUqrRSlgYxT+SSRprsyCjWS8qvNd/ JzsfIYVoX67EEUZ2rEv25/pgxOvgFpIzNaxDlnxOxZkq9rSS/rhh2+awMXLo49AJ TyaOOspwKf5MZJ5IgcV6MTFpSlWY8aj9L0n72PprL5fCmRao9lEVOJiJDKXGv+H+ MMvj2Y9VEH15LiUSVZc98oEkPgm4YqxJssLBZQQTAQoAOwIbAwgLCQgHDQwLCgUV CgkICwIeAQIXgBYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJkJqswBQkQ5EO1AAoJ EKrLMkNjAFLZaOgOoJzDpLGAckDlQGnwBwx9532kVg+L6quv8PQx3y7Bgo6w2B17 3qxyJed3efVAJxGf8qgEqArGyMJU36aw84vYTat4u41KWNw+0eI8QYoJchd/KqqQ w0sg2AvnuRbK1Wdhe6BB2Cn76eFO4krMu4EiIV9MltgxnyCuGnEDd7s8R6382N94 safhysAVfDXs38HYdo4A+FzDBWn5FLqenEuJtWcNBVWgZHyAU8zjaOeGPUfnHun8 gNpSMNoqcGSoAIf670i3wO6n51HJfGR3ifaGeIaEkLMn4DyYjxz2pAoroe1QB98K AOoMuRbd1yJJKpUlfiTeH9BRLwQ7EqsmZgiQlyHZxfkukZHKLzd1qnng/AiScck0 LyuyKqTw6BiRs8GmsBpSNHvuvRGUqYs/ORVb/BgM4O7GzcTwjszvzxcTgJI9SaIf YtwLxDUQrqKDRgcHRmSdG6I3uLyJRQmUV3BO8iXw4o+UmtPbr7cvNuQFVlGfc+TF 8M8h1QnuErKuV7kAtl0zMFagWKLDFUZP5vJmQkIuPozv72zXIhV+K9cP3LYcEzVp mbx66PGAgbsbv5OeU9gJfbJyWB6DGZ90aHLBwCHJhrxZSBVIRdquaiQplpMkRvR+ icLBZQQTAQoAOwIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgBYhBI8Xd3EYoz3am6SO YqrLMkNjAFLZBQJjN4MHBQkPDROeAAoJEKrLMkNjAFLZvz8OnjpkQjNx0gzlYtqT IBOUQWJNCZpsALYGol/Wpx33mb4i77mjtCoOJ7BNhxBFUxxJnSCzER0BLYzV7a7N yeZJ2mNnQGtr1o7W3l9UrqlRsmbabLnA2TnGROurkrVXgCvKKqIelHdGRMHO6Aoy iSE6/Cn6NGf59FbqyEoaX1A+y9e2qlz912bFjMrdIZCjLPd46d+kGZcZ4nJ3YxfR YW+AdoQ7ZfBepgs0BpxGtIhYDXWwclZxscKhODYzT/D6qVdwZlA5tyA9ZJw6FC8u VHupNZD32wpQW2l7bf8YsWatANI1N6wDOb7WvRMoX00psTGLTub87lJGF8FOjxM4 fCEO6kf4Ykj2eJf5Rnc9bpd9xsvlXhjzqxjK36FiU8JxqKR1oCb/WSe8WQQ074XQ 3H1lA0LWNLyghyWE4H9Jwv5yw/EFhFDkcBiZbXrFRohLZwf/vcIKqbxtyA46POA3 olcBUUPrDpfcBqJUaBNP/jrsJzYCTgdi/EpLNTwe/4ab7C1SZLcWm6WQ1IK2stL1 6TFpOJqGjcH/iEAqRTYbYa6bkchW+jh95TqxySuwcOLPvCRTO7Cn9BMRgiP1A9jU Tz4ICn/uFOTBniIZ0fdrryf9vyLKaQbN28LBZQQTAQoAOwIbAwgLCQgHDQwLCgUV CgkICwIeAQIXgBYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJiRkCQBQkOG9EnAAoJ EKrLMkNjAFLZp48On2IBKfNa8enyuLzxkxa+1cFFtxX3h0Viji2YF0piuSyTWLWK vtP1vfAlrXSDEYW35KVKZSiZaj1Rb7FfZXSwoL5Lhlxn49IQzBYoID3lpmgEXifd 4n0ExzOYJibJhAUKVtyO5oV6ffb++8ilu8VBXLQ1RMAraoEFboXXz27lXQi4zaAE vCOo1zNGrcRqkzS3wzl5f0BScNBq39wZDqm+6DkUHQB/FkIRQQCs95ai9qL3JsGP /5On2c8aJKf2HLeTT1Yo1GYcjiYwQDn8B591mh7SKQgVLRIed3F6Iyz+/Viv+8rX 9zW01KEDhhVMyIv6omefRN6XN9CN/rK5KRg9ZzXzV9wp/0Jeb2RxE6J67BY93AV1 D5PjbeT3wbWTYOaBqxn2yKofQhjS5pWwwKngGhvwrli1f8Db+R0yuloV+PsEWWAW oCmBsIykKAk4jHY5v/3OmIvtdOh08dhGm5VcbZ7s+J0d0t+iG0n2rTgOsTDVlTWv h/wr72hqOcZjhkHTc0At2KvFCRjlfSlD7ZhDhm3CQSFvyIVN/jqmQkA0x7gHlW1q EA9MyzYV9X4mqtQ5B1iKQB25IQorvMUli6FVVSh7rwUs6OlSMOnxDrFUu76XNaPC 58LBZQQTAQoAOwIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgBYhBI8Xd3EYoz3am6SO YqrLMkNjAFLZBQJhVk+2BQkNK+BNAAoJEKrLMkNjAFLZc1gOn0apoz0XikdVwpsL 3+qRJRJi14x7MHctS/p7ZyUviYmX7NkeQEicRKuE5K+xu0yMmpmsICvZrnmIi1cB 7EP6pGDZgYo1iqYaIyAmv0yvunm4ghhUS6atwJN+cfAKrUXh+ogZkaV4j5vuvlDt Gifawo2HL0dnidcR5C5PParIr3A7r5m0gI+8bUc1+wlXxOP1Iyv3hYo11qPq/Qu2 okN7hLhDmBhmXuZnwqJ8ymUY/bn7uk34PhAgbHlpBcls3LB0zSvNpPXmPSPf7Kl0 088ldRSiMmTAM6ZuEc/osB6gP4Ejj/cYA1ej7i3K/0zSGIRLZ+l9LstSLnH1Nd6m w+gAzMFoObdGBkUoKGGvArzYT8O8mgSmeg+fXd4KuV0Vyw1zD66IfoEfihMvEwDe DhchrWc9ZkS/10Se1uJ8mmKT+sm7j6KK3DgWfZnr8/CwThARfGtQn6bGcglf1Y0r X2wMG4NF76hoLJknaQ1JE5aYyS/PPeBXNQAX+wTt6wJuyDyx3APUbCNQu6V4eKH0 SgX/lgIHxyqqK6xqH/F/Wbdf/gTfD879kxEWSbg5NZk8Pk/aw9CgBI/XQg35EcL0 RD4ZIfqSAGAftFvSHqrXVOmwdDYVsMfTV8LBZQQTAQoAOwIbAwgLCQgHDQwLCgUV CgkICwIeAQIXgBYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJgZQ1FBQkMOp2dAAoJ EKrLMkNjAFLZHLcOoIlk/Q48vLf2P1aV4eAHLSbXwbQb9YUAw16ZkmH0MtKoBNTe +Ka/xv6joxKHL8jgjsUWBsCtVk04HzucJzCdQHHVfuFSFrqQV+AZv5lUeuoGVP7q c+drwgS54pjHKl9qRXknlumODA5K9zq2a12QLedCXU3UrGq7gOBEukaQeJvJVWKa JRFl1Se02mx2goFTkUmyTdVMMukI6OP1woPA5NZgApiIwD5LvGbx6GgiwXoN2K3F VgmNKWgDDdLYQyDhKmVakzLasdwLSBCwXvH5Ynss9iShaAQHvnpy4pjobzV+hL69 ecBUDjc6jBHRrx2IOwFGiaP6aD4FDREtz47Yx+XAxxom+1kOkXhb83RSaHc9Wv5b F1TSwmZ/bX/AMBxc2LHvSDKl1cTuDdPHnKnCM389rQLsU67edDiRgITILpOia9IV 2JROLKv52fW4Ee3oLAxHMDDVFsAQLCPnM6hp0Iyz7AewZMOPyKXVcAj8tkBjumT9 HA/EWwNPFc175C5QeiSvOV7PJk6Z2b3+dGzGM8PMv0vFDnc/naXk70Hf87sXLFXk IlgIGO2tltqL8oY+EOClC8eBi6+NdawBzUVfC5VIxYSxUOQDLtolS11K7aRpkBkH DMLBZQQTAQoAOwIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgBYhBI8Xd3EYoz3am6SO YqrLMkNjAFLZBQJcsIjNBQkLT1TRAAoJEKrLMkNjAFLZYqsOn1VikcHnN61UQhS/ /27thmZwxReWKHzI2upRrwitWp85/mKxV8c2B6iBoWKgPi6KQibtjEqFQr0Vw+Yt 7v/rJBm6gnOPAzWNxNAOoiTdVm2mLK+95raAGi7oGEt7tpwWnAGOzBJQzR5b+j2r CWxfDmmr8Yi7lBtkqXKwM4XGAOQJ6x/JgNozs2nZ/aTXmsZH550RnMA6KRZmHVPo lKet9VMljnVHLIGmj7ynYe5I+gY7SvAJQ0ezd7696v3PQZy2QuODjCBGxPf7Wi2a xYr0D7b0GabUatQYIa1mnbchVKx62suEk+Svc97VxXryZiLPMk2Zua/QJ4iVuBRO J50CQO82bfzgw0cdKuEl9ZaL8hsw4C1i283euoIVLqiZB1sjPZuy2PzbRDuueUts BmTIRbc4CL3/9Lnn1lbUj7m7L3bBJ6y54giRKLA+VVgEFXmBBywgpbCewn3B+DG6 oR23OSv9PHznGhzvXhvZbSRhA8WbNlf4atRlrEicryq0U3InJKNi0mVQwgUL3ra/ Lc1Pvml/gE8nkdMfbD3pRy3HVxkEqb89hFy0WS9PUoWIfEzFHFIW1fbty62wBBsI KxE/mUhWAYKmtrz5MLvT4EDTWbzqad+3LMLBZQQTAQoAOwIbAwgLCQgHDQwLCgUV CgkICwIeAQIXgBYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJZzTZ7BQkHhUwSAAoJ EKrLMkNjAFLZty0On3ABjKfIvxqMZLE0XKo8ybBl1AqJI6/jxtx+NWeKuLQsak/u BvssYe4twK6odXpDszxb2adRO+s+RzX6YUfh+yl4MSqKyP/4XbmfVI3He8MRU7yB Ah3LJt7j9GsENC3htnpKPfK1ci6lGPSkVeWKGFZ0Kv3eYaBvnGazLZUXwZ0QL1hH FgNPgI6DaaZHytPWhtgcuIgYwFAFfVhr0m1UgVfMlePoBvSLuDFyrpjVS3G6SKp3 d16NdfP49nnP9aef96xJSgmedMfi/5lduL+8d0/yXAb+Xyo7v0s6e+v6ggNl25ac vhckkZV6iAyVmzuKx5sG24D/g93kIPx9HkEXehu5SYWpJLtz8wXRY4q05bC9jRQb JrbKheELm6XPwHiGSwG1wQTwvn9f+N0RwogZRsbyB3J1UVbO015/T3mnJxoapk8w +zsS+OyxkMr44cJ61frShruojiWbMi/qUp4VQNVjgMS7ysBLvtMM/6I4VCsz0e7G DJuvJATopxEVg8VleY8fRZeOGGArWvM08jns6RyavY9NhrYutf43XhvtZRg+EnE8 Cqw8giVKE4yKjH84w98Z/e0mz9+V4pZrvKa7ELv8Uxqx8H36U3dNQVtdpPTJ04y+ oMLBZQQTAQoAJAUCVSOlbwIbAwUJEswDAAgLCQgHDQwLCgUVCgkICwIeAQIXgAAh CRCqyzJDYwBS2RYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZgDoOoKdOLLX7qC39jMzB mQvigcmt9WQzhTMhbeMcn9wHdydt0HEOI1zCsCzsUPaW8Q6tSTb8Ce8sbEg7kM87 skn4fzShipd0FtFaopoXMfl9wigSk/y3rgs84bytMJTrkx+kBtCAP/OUnvAwEDU0 noCFdoqajNQrKfA+OntoKqiOXHLv4ydYosPItEiC1g+qxDuZwQ4cr8Zd+Qd6REjf VPRFmnXCX0szc4cQ+5iEAlbOkTCnE1ZLuF7F4WGOTEFZgkd6p6pXWONF9MlPo+Na AUWhPAXu9x+6H5UcKUWkun9wLKZDVBpl938MrAlmk1fwOzP2QSfZGuDQFND3V87K 77ALpXtlJMh+RVZ7oyeEfSlWzTmlGCDQ+VfO2pyas7xFY0SlnxaaIEKajSVBX9QV 190NK10ENGllrA6OxEjXjov92L5MjIgbqIZKQW/fTokikLz09boUdluCljjRtBAA 7UF1VJRU8xKnLVb7siizngPRVaUsc4hghJYm/VcUAVBBY9GJDHYvSHzMUbk6tnsc sZZJAQ6PL0KBjE7Luji+Rewg6iPckngfm+5kjozpY4/PV6pHKtQ94uz31iiNx81U nkgNk9dR/LP6o73l2ecGostEACq2CEwN3c0nTmVhbCBILiBXYWxmaWVsZCA8bmVh bEBwZXAtcHJvamVjdC5vcmc+wsFlBBMBCgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4B AheAFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmg+77AFCRT8iC4ACgkQqssyQ2MA UtnOnQ6fT+xr8vULDc1RvLw+cEeBgNbKFK/8HgBn4HBmqEMrftLHEyUwAot+Fq+o GLrcJm1nL5berVUfv6c4Br3NR3eRA8TnkSWIgRSellpCR7GL2JenisT4ZMFCxubD sRn+GFBQACFmagsY/zrw5GicvvJR4vTUNUwnPyTvc6PTVvvaUrgA5fUATiZx2VF1 4V8TwGxLPUZk0Gfv1OIl9CZjLF7LcKw5bfIhcUgF17YmN+vqkDeKQc0DtGuTXGgH +u76hSNHLN2hj/zcTCdiu0C2kjt5UwC9H5Lz1kzN0+RAoOem2FYXoi3o2XWr92mI olrDaB1sDMMCGou1K92weMrJPwrZzT4gGvp2NQiN74mKMm7VQ/rR1Kt2q9MOx3En MDUVUxxWKyNLxvjcMWhDP2h0BH6XWPNlZHyGigaGJvVVMwufvQ1ZYxJtTWssHJPv NqZxa/wf1gtvejgm1qp5tAze0xwD6IWmk58iGbXwnFDWB127PErjJcQo0ajjUBmQ vEdaTkj5vh7XlmAuO3ztLa36OmdwOKGR+GFTgl77Ku0YOyoSlyLvvKNu+aAZWLd5 rY5bpza/jLQziztGtJYpSnq00+vAcmQBz/h68TUa2HRwwAM06/8Wch0mwsFkBBMB CgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEEjxd3cRijPdqbpI5iqssyQ2MA UtkFAmbMKdQFCRMMg7sACgkQqssyQ2MAUtmNpA6VG0q6QsCl+Vs/XLcPVfuNdrw9 j2Nc4UeORdvbnQMBuNj/geXAeDgBghqxEw/vV+Fue/K/Vg1oby1AzzXrT9ikl01k eusV0H022kNeC/DJ1opxFyekElIsrvYJ5ZoXCZRPjIpAGNU1uVKlT6Gqrj2YrNU9 IAFApjEiuXmQHW6ynIsnMv4iccazm/1wLuhmsy+bqfKUrkeVlMaOtNDA/A3k+Uor 7iM/QvzXAVlN1+2nJwGDJZmltQeltSupKxr23Vhi9CrkHhE0Jl5266u4J1pMs4gU ZK3eqIESJjkhgmmFdnu5rp7lcl6elx+N12JMmvrdYgRmonxvX9cGr8PRtRBX/vFT lgIi+S7vFn/3W48NXCt6cs60aOk16OgzsXHwb6NXHMoI9Gn9R4CoxY9hdGm1cU4Q QcqLbqmfBnS9rS6sryBJ5xMYj6KLhsqaAnfH9MQyGNFFkSXkAlnX9vLgwfY8vY2X zGalyf5wnxf2mO1T1E87NIVUJqmRTbKaQ2LVOFHseMQ3Pv6v/vqX82dw0SCrzNuU eJurcxe1p+NCasO6g4mnjUpYjz+xPV0TiJPuHr9TqEE7+DeuAd5vnigfODGMCYsV Ad31QFm61AAEUlXz10NaUrHCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgEC F4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCZd2ksAUJEadXtQAKCRCqyzJDYwBS 2RiHDp9PcAdNAk8Azn1JOrghBBbfaAzTfbHBulu6bHE0N8SxtiT2MzdseYttE+c1 iDclJlE0cBf70yEPbep0GXTixcTV4rWcRiUyoooRXgFXOXJ2kp/1fRY/AoGVMsqE ZEE7S/75yQzYfUE8DfoR+yYPbLVM6fRs/7Pq8+Iwq+gAyoFgQae15/NRkgHiZ72l iUQaRveVSQNqSv8EAkt9PBmB/IVo29kTPyPpWkWM7VeGL1nEuvu4ML6ROSp/j/19 JGr6WApBl/IYos40kO5T8H7B6HbysZm0Keb3lZDEUCrUFjdzDwNM9lyK7q1Niskr CqeL0CjMxl+YcDld99qcbQ/Iba90N+1TuN761TxA2nFHQT+AbPHiRvVkz48el6UO joQBj7dWBHC0iuyVvxMBWzWPudUiwuJXmHEtsW1W4hoiAZRL01omUExd4f3leQN/ T7PX6ikE9H6+PGOoeMew3gF/GjAr0oozdsO5f79wU1iu+n+n7Z77zjidzPBv01dq SrAEE89HyEZBaxEsy+mzg1qCM7NT/CRWGZ5mzBwdrWJ6CkTAjD1Zd8BRiVfLUtvs j5yiYpE8Opw7kr1P2GfOURUGL5YZgLW0Lj/dckFnxaGQHtq9LZasplDCwWUEEwEK ADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS 2QUCZCarMQUJEORDtQAKCRCqyzJDYwBS2YZkDqCSv2CzWtn0wsrqdrFAU3jPiVeh o85rlG9tRlD6iLCAihUxNiRAm219ynKd0aThEDEbLY+ZNSSCHRkWPcG8Ejblcq3+ BtiLrZTNoTj1rCVi7lRSmsYKpKEVUjQTk3zBWUwWxpiqo8sodOq681AH//JJRJ6c p5IKS9MWDKuE0wQpk399uYdqWBshlhyhUTrpdIbLa6Bl2uyoV3An8ER1QHfbuwGo oKpA2UE5YsssDtQt/XTuKgJzZiYlESQaf4oHBtoYr4ZCcBPJ8QUbiOk6RXrTJwrD Xi5ork7e0VVlsV4slAMaviw9tsGCgv42k9xvzEOF24td9hq5JaeoWkVJLAvwwaSd sCXWt1MZBTSV02UsesxZfJsELo9QSmKnjvUM/hGqX4LW24LBVuMc0GYZE9CkJaPQ 3NEuJO5hvAavLECE7ioyTq5FoneBUHdE264R0UNl7THIYKqqBCxs9M3cNCghU+yT lNTqPglm10ls6j0qNdQEAkm0sZlykeRCbqJ7YyH0haa8ATO4HFDQ04CvsR7pV135 xo5uKLuKzO5HYZLNg/ilLfSCStVda4LH4p+010/+MvVIOvfXZuWSU61WYLoVM/5E sY3yhnVXalcsDg9Q258IDUfCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgEC F4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCYzeDBwUJDw0TngAKCRCqyzJDYwBS 2aS2Dp9UO7I8U8+iJrNOBRcT4w80scB38uJl938EGuF68jdFdvZcgTLgKctqVG9w KsKwuCDzDhW+bVUweblfnkSKRq1V+6hX2fhrAgUOZVdelB1cwEE2qy4sdILUHqGA XefDtvKrWn2UNyqw5k6TfTFgz38ZroJXL1Q3t0rfEGgQgdqzcq6mS0xpwyAuyH+x h4PnHpjlfuOMzmjyfA9hRPisawQwf6tzcO2YFF9SCvK5c0EauhRoHH/mW/AHwSMK dlH9nLV1ELvBC4bn+77bGfou3pXiEHHIIB40bY7CMtOYsHegGwJ4BSI+oj+zerWk oKKmx3Pt2pdcbhcbl/QkhELUAs90UbbWiUekVY/K6xMI2hphU/zOETIDlSYaeZAH N52B1WNA7cCL/M+kUgyTWtGrTkFaCEiEGNJPqUjJXn57Xmus9fYxSWbP+l1jQr++ qaqYJxzUYMlxdfSIs2ElDRmU0TZ7x9GlNTudZHPt2O1f7vvNvGX10KfSzPBgMKYV XCXPrOkJHpa+fFRSTXYMg2FO54ZCVi+TvR6F+oHVh3tA2Zv7a6HZ1zNEn3RbOwxC aRvNPfdj1PInuoo4+UQXeAdXQkivqzgJvbjSBscuYa04FWNH81dl0wLCwWUEEwEK ADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS 2QUCYkZAkAUJDhvRJwAKCRCqyzJDYwBS2RhSDqCQg6j1nrEbGybYr1dvWagOcwy0 p1/oKzDBiQ0vPwYpiA4d7Wfx1JD5gnS2YOYhgBNjvoNQZQAh9WzjIEYmCA77zyT9 WnaXZvDJtMvqgIqT/Lvxqoxh5pZwbmMiGnT8ZPXi5mxlCKgFCUaoEr24DpVHtv83 q6u0YE/w3HS2w4Qmtfgnc+7i5Fjj3ZZf98zaDxRzGRaavnh+G+M1Pg4z4pEP8vPz LI7+Wwmd71FIMqEVzVB8ra5uJAOwo7+g5yzGr0E9AASpI4Nkh8vb9NopLPEVofad lyM7egj1qmbgyEx6Jowcj07a31wSrToEU3R7DD2+1cwMyzNIVEEqccmRuH7lnjgz RmnceF6U3ge2kYhRyvJwPmhASVuAhore9DRNjyljK6laGayxp4YAW7TDm9G3rpGU GmTgAhcf5Nyrztuboz7Gq5Z+OORzhL2id3zQIMkV1upIleeJ7eppEr7IPU/69T6f 2GCcUKydClgghqOhip0nVrvlMUkvmO6dsDeMqL88VTycvJJW55ugO7TOvnwI7LDE UkUvKAf83fSlmpSsNJsSdOBXZrekPReweEqz3kc2FWJyLx2w7fLQbYlkMNSx2DoS ibsqjGPlvYwW8sMsJ88CRXXCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgEC F4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCYVZPtgUJDSvgTQAKCRCqyzJDYwBS 2avkDp0RxVxnyVT16JF9qe2CYaerV/tvJM427Dg/rKhmknpDlUW5zCU0sRG22RFf x3oU9x9uNb9F0qK5zQLI84d7YFTqQMLX1SkUCYiDhp0c5mF20dXrKoyOZmqpajet DfUkNCqAB1FQnraetNBtDo8subJW6GdilegjM3LaGyluvftJiZ9T3CJ1Dn5nE7h0 7GoIg6OivmdlsV3EOXFZzymmzc9rEA5IHVKQlXSAkXTdC+G9E65Rzcoj85TB2Q0l 6n9Bfr08UMQhR8itYQrQ7E2kthmP0Vt+pqahwDZfeBWFjkAJ2eXVKXhUGEFR11RS WL7TZxma6AZdLWkyRhbHA6h1rvQK+jUSI09PCsJ6RxiF67I4x1wfvqofqyRXeRBu VV42O2xWnxrGo1szJ3iwICyAbw1SLa/9YhIDezq2OkXMwyJa8Sq5IUzJXA05r7q7 qXmebveBe7kT/tLyUVgZ0wuttMglINNrEWFGwjbcGYzrykoldaRUPYUE8a9CaNR9 n1LLP36UrXRKBvbo3s+q3Dv8gGUpqVWN4lqCBRkzLaILZUhcwF49IoZ5vb8RuP/a cJbJjRFRH0/rsp3V735coYTt2+7NgoQxRg4kX9yE796G3vxd2Pu+xEnCwWUEEwEK ADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS 2QUCYGUNRQUJDDqdnQAKCRCqyzJDYwBS2fVSDp90hsk4Fx/BOJ6qMZUaV6047viP xR5PHC7YhMYodpUlKkYZ7FeEmBRT9Jufa18ZFvvKw7Loy8/YECWT5yfWG3Sb4kq8 2gcWuMnf696vLa2gRxl051xc58drmdUevFcmPMT4OAIH2hG3Xp/ZD5eLsyn1KMS7 2OQcq29DlcFWzzGSSOEnzlEdFPPBfY6GIvRTtXZZGBgEJwTI7Hro82NIwzslQcdu VYTkJO8TKpqWD3H/8jHNXFIe7u/UwZVqpC1zb1VCQ+9B8ou1+yFSMYte+E0o4PyJ Lfx17ZabeC83l/hHPjzCe4lcMAPJijPaJI+xTWAUN4/p8Y44wRoNwrBMgPeXwys0 qCO9o1lbiR1QSynZZpmR3quNfMWDSa/Dg6V6/u9mv8VVCm5da03WtsLDs9TQZ2WU zFdeDxR4hsac3KN/jbmFPVw7XKj0y69xFMIEAc438KX9X0+490onWB7fLrBn1OtR DCF7W/PkJORCCIKc1EtSErN8ADevv7lh5icmQ3/2sYrGiyhrTNjQpPdDgan6daS6 yumuMdEw/r2tW71VPaMhdyQOgEGEMh/olByB3pmODUvKP8kvNkcvQG7du0wZFTEC 4CqY5fT9EJq+vF9kP90A1NjCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgEC F4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCXLCIzQUJC09U0QAKCRCqyzJDYwBS 2Us/Dp4rVKtUORqUbcD6+yW6iwvi7al6GPr52rUohCZILVuqcTCpY8g92u7+HTMw U0VWJBV2mxPtfkkYMsaKkZTnznhCSqN9Y/1fTZdBNtmZkvx5DyGxq158KNciwM6l cAw99FrIxSHRB1SHcaz2sR2LOWQNZKGhA4wdcVZsIBL0Kjr3lr6CgAg98bF2Yg5f yI7BsHvLuFil7EGAa9+3ngqWV5gny3EllJeMOH9fcJ5Kh2uSJHU9kfkyTuYQY8Hy 7lToY+z4jmGQNsae9iD2OfeQa3qERNTxT6mxFxdlDD+1BksrQiz1FiQHmrUl882z oJe7ug3liFVvhiUjik/2cm9nHUdxB0e5ynzGCqYHgvi2G2WHSR2MDqHn5LQcEcTd 9hokqh280ejYa4LWsBQqeYpSgE9FLO5rJRX/+ETOfk68BNKlGltMakAL4L4vJhKd Fkzyniq9RwwgD0R4aUfjD8UX9sqAnZ35ibyskMmIu1aAPX+nMQXhr+kHDuGv7ga4 RPZIMaVhvibWaiL/W3CsEakJeMVxsdJrWsCBdpYm2k7ASwiKzHkn7Zl9W89tOoYW A+UluDJOhCWNfvafLodQRojqqx3boZutV+uz27JmVP5r4k3pReKLLDHCwWUEEwEK ADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS 2QUCWc02fAUJB4VMEgAKCRCqyzJDYwBS2X+GDp9Iyh19ICgmKigudHjrhhmBYzoV 1O/W4L6qIdG0TF3G8Ty//rjvHbYuIEGdYQC9lmq0BdN8xLN3RXmn6pOl+wempC98 +CyZhohtY4MTELl3vfcqYX7X3nY9hQh43Bz9d6KfzTqnZ+kKhF2OpQZqEnUSZBHz SG6tddPwjehYu5OwuwDr9ZKTs60DMZj/lHS4gL2zD2we38epEk2zMPGyNpuElHoo nWwpEKsDknREZ8+xZKI82CCQz+QK3EGZzoGSQifMF9R3hXGcV5Z56K591dpc/cWF Z1k1+0U7Kj1/UheiSbtG2tfNcD0RLvEpjEyjAHl/evYX9zQlnQXL5SbcAmbp3PpP MW54s0Z1tAYUvzt7czA668HcjFt6x6pITwLTLvHr3x8qJTguKv6PK4pKdOMa4K9x QQ7IE3W4XYlldH+LI74F67yKOQ2fkxfSCDTdApL6i7AsC7PBv7oFFhMrDoWiFDWQ wQ8W6egSW4PUcvvF4wJ0y5nATxY5fEz4Ei5q/YnwxzWju9chQoBDpw6ns4QP1zw6 4GaVZe2eDpliDhExlNysFPWFq9R+L9mdn8ePrHqr1WnuyGGhLc27QhgnhHwgCHDZ 5SusBTnHPRUsbSydTIJSHWTNJk5lYWwgSC4gV2FsZmllbGQgPG5lYWxAcGVwLmZv dW5kYXRpb24+wsFKBDABCgAgFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmbMKm4C HSAACgkQqssyQ2MAUtnVpA6ePYwta9SIyXHT7YqcU19NrbcNzcGiJBG+XF0OHNfP G8f0v0GrBIhPkyn4jwMeqyR5f8JxNX0goVQC3soIKTb3v4bRTw+4dQkfP+3zqE38 wYwR1dclyPaUEfOKTD9uEvD15c9seWyyvsMu0EdBytlXvoUNeOLOSIT24WiSq4mX BfwTHGUojbGK0KpWB+VDO/JWBbz7kBKuzV9SZvCWQJoQDYNdCK/mbiavF/UjzIrw UeZKECljZAzrxRfhSdqtmxS+yw3c3gdYCi//ROlGwK+F3BehLt/hQbK+ypLKBdUx L7y3VJMbt71n9HkkvbkS+9UW4JhmgFbrVne9DH229/rVtoWzkQxwsDQA17+jW2u/ Q3By5QqMb9QwRcKqdDNRqmLwFiTq1K0lQMl8O1dvDPYQcPQ7ZbJVsbY/lymdL1wu t/sorROFDtmvF1r17eXikzeykeItSKYyoaJOBd5+LGJWxixBWvo/bkZDi5F9naio +4V5sFcDHxPYwwb8u9b2EIcBEuwd5ijeuPKsFKtyJSErBMqGls7c3C2tHUSdheKR NpztplRvQrMKClz7Rovm96YVyuWy8SbFNl3vPD6u7zfGWArd2AATdCMSlZVIsXtP 2zqIp0tkwsFlBBMBCgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEEjxd3cRij PdqbpI5iqssyQ2MAUtkFAmg+77AFCRT8iC4ACgkQqssyQ2MAUtkcng6glbMumXd9 iyq6URE7MZGiYT/7gCcWyOefzzYyWv00Ae6prz8ePaR3I6HYZUeg0WomFYxVU8HX 8oldWg6gakF7oYm8m+AknseK8/tA8qGxUimPLvBKwLKoRHVnUXab4PR/nMBQ3lw/ DZMf7qQwYU93ZNVsNRJTHhGnFilYQ0VsaQj2s32j0s3oRNrJOC/JIpZJKlwxYvN1 0dsM1J1SKxgqrHwX6o81q+60xn9PupGE6+3rFMXkUz2ChluRji45xe4kuvD2JnKo cxdWw/Y1XMcks2KLVR1ErST5fsAnuaRJEsHjqmfA5Dc2iDyzR7bHOcr6vKcv4hFJ KXJi3DRuNdm9Y2WWRS+04v+Zk4Yj6VLIP5A5e+fIg5K3d029Rcml2BhpS1+GPbbD B05E3mIxzDhCKwxpf+Nnw9dbY1jiNOfEiOLm2UMZMYxdGg450RyMm4+RbBWBBO+K Uvm9dVWwtseHMnjYoDe8tbbJC/D6o5Sgaw4ZgTIhdvZaop0yFYTwtOKXlP3lSM3T bVdMK5m4EhQIhkxTredeX20N3nWW29pR/BeFR9IyU9r9k+ZcS30YI8SqUv1VlSBw vLUcqJ4KTNc+wjneK+Z9RuKNZ2PRCG2bqYG/n0jcwsFlBBMBCgA7AhsDCAsJCAcN DAsKBRUKCQgLAh4BAheAFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmbMKdQFCRMM g7sACgkQqssyQ2MAUtl6dg6fW1qd9tl2tbyVq3fndwx8ndcBgynyV4CLjH1KHqsB WMcnduKFg+2DxrPb2HldMnRroBi/0pQYGH99aHrfZOxtKoHglBcfdKO8MJm1g1X/ RHz1hn1C12h/9SEnhvkUzs4Eazi2hEvlAHwXnZn1iaZ5dc41AHJlNf3ufXXPXjay sB9765AphjpCIagJkqahliHCtf+kFe+hhQ0etjKrQ+isJZ8tZ6MVTrTsDsY1lRwk G9le+IeUvZle1lwUnc90+YQ4ib02y191ep9i8hvvnRROC9bTDYfNHc49aO8zuAxc 7eVAaL0/hrS+cCtoUHaQMAZZ0kAQOvvdSeWxI2APfaM0rkfJxTW1gqZbnTtEEvTm yzo4c9KfJCIU1RRAZlHmpVSYUkGbiLFYznrd3dCIxW9+7MHrytJKOnWp2LSYEbeJ yZTcc5mOD61spIb6Sf25MZNUZtngW4j5Nz5FQ4mriyipPjetllSXxfptgkvqtF3a qhfi761591ygtyDWOYLfTgfkVRhfChThUXI/Ai0non20SDkRk3MhcbyKKrS6PDBe /g0dm2IWAIIO8QKT7dHo+Y+yvNpGq7JgCc08wYttg7X4hF2gHTzgOBcRjbQx4+6/ 8wJ7OOrDwsFlBBMBCgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEEjxd3cRij PdqbpI5iqssyQ2MAUtkFAmXdpLAFCRGnV7UACgkQqssyQ2MAUtktqA6eORgm8s2d /zw02a/myc2hvBtRZVnNe6ElYYUTYMGW4DWj9dZWRHtuloA/ayMwNM+vtD4kBTuM K7iyhk1FbFt5j9rmSpNcxaGNJr2nBrQmcxsdIjUqmyJYPJ5kTmF5TlyY8ZR4KtR2 9LByNkSa8m05ArbbVcQjvYxVvj3ZN3/DCdeKVSqhqO76dEtkBev09ik6tIUGiy0d mXzN1Jpm1MF4gW+YHfcFfawAx5Cn9kKs52fpum5hgDMrzt8JZuEBRlK6dN21QN6y YrX3omxsIo72xEbD8rxUbbiCtj3GQZ4DAE56crVLuiSvM2q3IePCq+pNuH9zH+lF +8mP6RwC/sNhPv+wM4kI5rx1c8m/tT9PWLrjQ+LMWx6NoMUWLyhxlF0KIE9W1qLz 68VUGFlC28qznUeYR1ddUWHTTSibyRZM2Xt5c5e8hRW674KebQ/iZP+OQixSfRLE JeeYKYSR2PqV9srZ9JXUy5X8Sl+K35sH8KyXxuzEgJOxkZzdtWSTdlzI/wenHtoT Pap0vAzDlL5CbMAptjquv9hI8dMTL/vDhKhcWc8mwLXz0FAxFf5x788Qw7+0S7dU 6dGQfDbAJe1PLKrbe46r7jcjLvIVpjG7AgnTVou8wsFlBBMBCgA7AhsDCAsJCAcN DAsKBRUKCQgLAh4BAheAFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmQmqzAFCRDk Q7UACgkQqssyQ2MAUtkoqA6fdTSXxiMZ7Iv8u8zEvkrziH3vZXpEv2L8BY/vlMvQ KaVZKgvNg0kVdx8aY532FH4bo8VfwqsEamXr9YPN4AUiyQR1qko1mjavMx0HOTcf uPtDQkIBX9hDyecVcHfqZCkrKRDzOsYjPJ5c2gZbBNROBRq4rDaePAZ6M8i4inCX DvgN8iirf+MPVH1VSTDWVAClAbxYl3fCAvZzkdpkIjL/6xtExQmXe7Gs9jWS3mSJ bo+MccS/c8Rsu5ZDpRjYquQbeemnbGdoBoLtd5VZvxPWdLJJtzl4AOL+79aDWmJa 9tJRD+L0sGv8/7dkqzU2fZfIcYmgSdSnxuXUlPdOue5apJeTziqNSYUUOyB4aoJm HBCWyRbmmZ4nwcvYFrBOimIz9MOvzAxjTlDbrwo89wnR/BzYFtDVGJD20nzXt1zK yR81OnZUAdAr6hm4Gxdehz4Y9biTMYrXgh5WzasCB2PYnBodPazoTM6VNFIEpnAY Y83v64/C9EhhpdfVeopfCtdcZQiAiSohfAePsb1tfo7FAPGRjqhvXJUlpzmi027J w970oW4z2KzsNQ+JP6aylmR8+yhvbNWwgjq1eZRzNOnoNgD3+dPqcNupMr1jmHj0 mlVju6O2wsFlBBMBCgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEEjxd3cRij PdqbpI5iqssyQ2MAUtkFAmM3gwcFCQ8NE54ACgkQqssyQ2MAUtkJug6fRRPS65tf 2Q6ZPEhm+Qmsk5YSquPKm6xrB17hycoNeekD0K6szV5rnTrTjOPe7J8I5jmsdfql UPvkclM4yY7odWxW7js7sVZH4GlE3hPqySMpvr6DLMwmTS9vAL0kUip4HCDofYLG q2Fp0uqlfeHPTnZytINA9Y2aqbR7G7AMrLaYpPsZZ1ivQu/Ud4PEWXEaDoSiyicH UXq/DsYTkk6J7oKG2oK8wtnYcSyQlCglZbAlxHg7H+1HtDZCuSYzateZDV8iq0q+ LM5xN4Ro2fHuz5+RBRu2VXqpPlW1DyHzoGDDp9e2trpSCAN2SzkIxwfPkH9tPw+Y bJHDB7RUb+/JXkew9Y3abrIrowKvaSfO40rNBnNiEhhh+spVyrRzGjKeNfcidI7k o+JDq+F0xVHG/rM2WjoMfnDzzPoviBYZDpvtM1T8rXHliAuTiAA+KX/LAvqMHYyO GwpEH5+CoAgVjCy+J4gvHRPdtBTLaKz18IkrqxNFEM7BOrJZHlU4n/twZz1sR+Fp yeHsYv++eqebLnn89Gj0zAJL9WtfHutUTkj+lDjETFnSrQ6bsk/wvTU0ST0MY9CY R81oSa6DcQp4DocDolBxSJB5djjsues7FYVZ40O0wsFlBBMBCgA7AhsDCAsJCAcN DAsKBRUKCQgLAh4BAheAFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmJGQJAFCQ4b 0ScACgkQqssyQ2MAUtk62g6eInZSjfcHlR2SHaStzxU/wYi4qzgNIz+FcSmPp2c1 G3+iE8MQgDVMnsN3E0x6MKq07tzWpEZumoP2DSRRE0Lxt/RX5NHwjhRqljM7x5ub ebYvHh/3tYYuzwtU3hRR+3Hmtu5UL/MYwOg+k2DXs45i31s115PvXfxjDjW/Cv6i fILUDwdTt1/iiXmxMbRXnkLax5nQL2ZChns0YcoU8vHLNonU5Pu0MBoBgCM22Urg DQ5uIyGjFV89Na6KdXvZK/DVj21JTpcF1gOqnA4hnoWxB3CPFOSjsq5yZCLl6btg 7U6fwii/UAYv50ZQghD3lqLDY2NgQ1D0viD2X5zLuLp0qFW+IdeC/a8cSXpNW1Ce H+gptoY2WcuQLtoSL0/+x6tHttzJxRLEbnEWiqFqrCe7KTLdn4XgVUz1ZxAmxzjJ bXhQXDR6nTON+LBoW+UVwTxR1ppPtG3cNvge15wYZAOdyaAyAlbHC8F6cctTQIPw lflmM8+AJFrl2sEsd3ZwBR/dP7ZAhNW3y6OqI2iL914LKEJu1cC6+LXsWqheh8G0 e8H6MtFDwBBhl5qFtdzbW4KmflwK99hFhYEA4HSxSz0BEYm3O9S8mknKx9Nh8R4y UV+FLbldwsFlBBMBCgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEEjxd3cRij PdqbpI5iqssyQ2MAUtkFAmFWT7YFCQ0r4E0ACgkQqssyQ2MAUtnn+g6gpLWZ9IIJ QN+tbHAo6IlVGaRtpqtRY/4ED0+w5AdbFyyA/9eMUjGl5J7v734rW+1TKBBl/oRT 4VM4K0XcIKKypk0IaEVBfX10c/66KEnt/lt6IBGc51+pvs29oOqFMm2rtfYyt36E kBIkaSAEVVOEbLlWkpqi1eQTpq8ZT19ydkyAzn2kJy4cLQXitiIo/wzW6k22oAtZ /qwuG9WCgp+GIOZI+ZOOFydLbj/79o4i7hZGxINjLCR3+GWOl/ao6n1AAy3xlxWf w7lwZfC9NtyDsPbBH5nJ/Gy8UA9i/lWRhF0Z4GFplqeg8q0L0ktIXTGjq7EKku0j T3257tj3f/yzB/NvoDRoWD11fCVZ1Q+Isg85rU70s8UJdOXd+NfIpJwKNCqLI6wH JWmTlWLV9ijsMq1C5IZ7BljpHkO6mAvZccQJHYEA6Jq36G0muymXf0+HcAg4ktPB 7D48B5fJ+eFnCy3HHIfEGI0DafgozXJN8TuYWgEvM4tS5FPjLiFmDUzn0qn7roZF U1kRsYqX8V9TJ0MVr+yvnjTLOUjoUetxSgqkayRYN5KJ/Qz1vcGOTttO+RC/10Vs ixTCAJevNnFT0OwkWEwNuciyAl/NVxRA5VMwRLllwsFlBBMBCgA7AhsDCAsJCAcN DAsKBRUKCQgLAh4BAheAFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmBlDUUFCQw6 nZ0ACgkQqssyQ2MAUtm1fA6gnRkLxzwLQY+crxelY4ch23Tmg7M0k5qA9PduGXVI PfGCmWShO5+KzPWby81M7yscomgKQ2UeK3XFEC/xwpcvXLi6M/3yiZBn7sk6lcXG RlJqgbzTkqy9L25gyA2jE7AT/dZDdsYB3opLiu+blf1vHJZmjBGU0wCBT7Uja2b6 coDDN/bJvwn3lartt61p/EVx4N8DWnQBtPy6rN2J1mQgFJubUp92Ngs7vt4dbKxn C05pkdrVGNcWqXnbLDoR8/33CGz4VO+Dmkrq4mWT5GA8Z5LMa/S++NL1hkyWWCkb SDYw2sqc9Oi3s17iXR843w1+qoczD9hVjCGi/RT3so8EgKZIiGhPSqSn4cUSM9Jq GmU/wnX/wh2e+1Iiz/hJHy/DmG/Rva8+CM9+xidIdCPKtb6OxElZ1wFGj2YR0fa1 8IzkuvBB/H1sh04+XKPQ9E3JNmZJ01s61fqirvw8cx8q9iMglYmUOQXYZJUR9d44 xixIl54j3G75nFVN52wte5R1sAIVl7kZ8aHGbC7lB+UOcL2IDjuKS31T6xeSa03C HALeUhxKkVghyvCuK4L3jFZxuolYTe/Grb7/k6nkjFlg3+1PaYjdCkHfIFwloS+x onnR8aI4wsFlBBMBCgA7AhsDCAsJCAcNDAsKBRUKCQgLAh4BAheAFiEEjxd3cRij PdqbpI5iqssyQ2MAUtkFAlywiM0FCQtPVNEACgkQqssyQ2MAUtlazA6fXmah+zPr Uo6egmrrn5XIch6V2GXlavrJazgoiTbxiWWDdrgvoSdWVZ9iMBR1MxK6aBRaaPD4 3r4Kk2L3q/P5ZFyZXdmRZ3Ko6e+DyBz382ff5HplhgtJfgpdAKRXx/wJLyQwKMYz cxyQVqNOwMzRPZNojk/aCAWvngbMmsAi47St008NtAiXkp26oa7ZGbtF96ln3NDj SUamSIiBqNA8dfCV7OWU9rkgZoRnw/5mCDyr0uwVNDtWcx/3qvaODuEoZhnyqI+a PWPPYANeQyeLi6YFL/KircJlRXzvdekuQSuEP1pOpkOT+0av6078GmVN2LMQvGHM pjfe27Ru/q/GQZFXzbJTtWr1LLEcTF6tr82ebufDq3YcbZQwRJ0H7+7ZI/KqQ+GX NcbcZBAhWTHkqu9IVjESublbBSm+So6xKNIRETdRY73m+vSG88P8ylGEXH3RqXk6 LsPEbbTybGygxIzweqwIcoE5UAJ38uyUh5B3T+WHnQxzPj5IqkSJE58LEl9KHS6V J6WMU7wuX555VN6rvGjK4XjD/M6cD20q2eH6nSZ2c1xYORCMBul+labW0xfLOsXz j79k24GniOBdZou3D34vfq/SdXYPOnyMvzGho/HhwsFlBBMBCgA7AhsDCAsJCAcN DAsKBRUKCQgLAh4BAheAFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAlnNNnsFCQeF TBIACgkQqssyQ2MAUtn46g6eJDQNUOuAgVcJGdVNO+A4HUx0kejBrFcc3eyuLbX7 AiqultvSuRYsq1bSv7xzqYGgzTC5447szBiqK1GDGjPUl99MG5aRn3Ni5bzRj5HP 37LVwKsMHcZu3qlbhHctfnBKslpcKQubz/kSIygTeYSwN+50PfJ3S0v1a+sJzVrz +X0cGDlBQqKCI3Sb1FJCEUQh4qj1OBXEe+89dydVNQ8RizjceqMhmlvEqwBYkp2B nm//FnD7jn48hf0fQD+aOYkvF8oB+QI2/Uu0+qyYPE+v7uDuBXSjhHRscZMLPHe1 SFF3Tzh0oWLVejZybnqVA4MFwEFs3zfmbOxy7EQSApRmWaiBIDRwTo2ASx4TdCqW UIQvFo85RcYCDMgwlrVYW0YlRfa4RJey4y85OBRtd/UJ/eOjBqGJY9PViUfMGghD 75qHob4+UkocqU8koOcH0z/WqqXS7GMWKUk0bVF74/lUYSWjLGeiFLvgVkxf4eue ZlrZSxDOPA3k6fttjZbtWGNOWWoBZZlnVhhL2tLc34p/7+BNdeWl6DcEPNTDBXYX T+nc7hTVhWzqZbsIfB+lOzueofZM8yZNDIZq0Lf1RE9Gf1Lw7Hdo0TWttXhun0w1 mx19OsFOzSdOZWFsIEguIFdhbGZpZWxkIDxuZWFsQHNlcXVvaWEtcGdwLm9yZz7C wWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKq yzJDYwBS2QUCaD7vsAUJFPyILgAKCRCqyzJDYwBS2X4oDp9xT9O+VhkAZ+5YJiLz loi33XZnfMItOrMyVnn+Fntf8DmurNbq5J/U2lGY8bjEotNN25z3inpx1SMHs+A+ CrvwiIAQUv+1FpWnJDJ6vMdT7QPcsObVL4KQv18gYlu7c8vKwiXTdm+tsEsFGUPL Wm9NlTvbJ1llk3sp/3pGQp7wPWVogPxOZsL6cCt3NI8IV8iIQrmAfwuKzLPizVPq 3cWwsrnyWAPtRsif8CuEyWN+2Z00VDthqGLJz/f4Hvblg1bgnMHWlAnQ1r/f7CzT Y73Goy4EMmZmISQA/SNCMsc3j3Qp37nDT/igz3iY+5R5O0a2uRHMk140p68LfUvG kzYAqF0uGsQIXmk8ogEXXsuF8TDR+0T5cfnF67aETQ9hUPr+I3s/VKE2DWkDs94W lO6U+qYV7GL/4RpsP9uyuOdsepRCPNLV+REBkgefr4W0BktsbXszWKKWk/aU+jCx nLkIURGyw/6otAHeItDQoqivTm84P0/TR4LlTjW2gqFuXw75rj9ppWX5P/jqUjER PAYFX4KgS9R6y2gq5pJwem50GONmToY6QXq4uthO17kNy4UqEjFGurdTFQNGi4p/ 1P+XSdzNh5vYRqcf+mCNNeYHu8EqcurCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJ CAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCZswp1AUJEwyDuwAKCRCq yzJDYwBS2QfMDp9KBBMNNagHPSDfpfAB/JKcH0SbxFifAzK2ag7Jk6rWCKjAlpCH prR6Ah4sXvUZO8aQ9sdPHkvyjkK59CUIy1TQzP8hnI4Wg37sZRcJbW510K+FA7uk ljMuiXi/LTlDHpw0D/8Bjqz+oU+r2E+986fWf3rbb7ojy3GS4aWJDs5kbiaRzn1e CYeKaoQHGUmQbZ7sRyDzxjeNryZKaR2Ux3d1NnhPWdYZKvY1KGeDwXwZS9cMQVBC 1n27sCOfuUgEu9vnbNsBJs5W9ZdWQ1lk50uwjQu5BzI6Jic7YjbPSV9c8yDnYuIy 1mw8H0RCY9QNhsUryJBT3K3XIUlgtzCSm0JLdDw6mPJSdQRl+ilVpF2gj5ehiugh Q958XT6Kizgtwq0N6gMey+ILEGuSser08Mxw1MbrGQSXG2voLlLcam+NIMVMvuKB Va1OebL8LorCw+GyujwhD71lpGCZT3VO1Npvom7dqtp8NktoEyqTqzOsZCtkyQyj LJYiHbIN8nxHOvSBSlNIu8sbRaxkSf3v+GrB4EUD93y1pHq6S0Ji9GGRFQP92MQ1 bpHqojXtmv4mZmVqCKpbjWLTarCfRxe1rrWiRzEfXLolH55l//l3mwbLzGDrXIzC wWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKq yzJDYwBS2QUCZd2ksAUJEadXtQAKCRCqyzJDYwBS2amyDp9nyo9hWHCA+MELnlAe G1X+tiY3CHZ49wddrlY03pR7C6E0DW9Mmld7aTvs/Uctt0TrmCniHjLWMwC6vI0Y c4V1HUjIDBq0cirg+ymX2NYI2dIhbzCGnZFiEevKlh0SbZVtCvsycNUiX2jOujJF 7h7X9mFW1HCqKp76Q/WgXMVUORLeceGE6RXK09Jew531fJrXwK169GNZQsYqqMVf T0KSyG3V/rE8Zlcx1U2DrjJb30/PRp1hATD5KgQtyhwLpYKj12Suvqu/TCVEoCWq Hd+6El7sA9xAKwlwe+QiUeH/B4ZMd08o7LhRQKbBRVR65dHBG6QAVkbo7PLcxtBy v71iEqk6NixsWoUtbu9KIfP5WyyqEBlY6rZ5qIuQZHZmVpcO131bXYq0CjKeLt17 I6SATqm4W3HRxJwHPhIwGJ/4S+taA6agGd4qMBSevGsBhGAYTznWAhtRp7MasMOy ZlXS/lLkrSswJVpY+by4mLUWQOdmdqRtdT1EFly20DIPHyOioPFcit93XAPAk5QS T9qrdXm8VUiugTvd5ZAW9L1vdrZI2rvuouXng8HQFstpwiydmtFFU8RUpNRnj22S p5cAhSdMCxZrbkanprczP1iBnyrBfevCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJ CAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCZCarMQUJEORDtQAKCRCq yzJDYwBS2dWaDp4wru9j9e55BR8R+XLl7NS/2OxTehXhnZdVHws498buEX1/Naee yAgcPAQZs/BlI+59w9VXSyoxmTG9ZwEZZ9jQZTKWuVEa+MAXasKmrZyvmPxNS7Bx CIBhxEbJMU4ZtcpuF5b5vH0Npsxgi8axHOcKlESa5zCcO+6uoSCLbsC6QNjIbrvJ tMBQ/fFPnHoBrZuuK656GbKdbkpLrztgBqOONCfjgtSgMg9CTJ4gdsty3c0gr5lz x1gfr0qLyg8U1vMvhwdz0JtoHZnUmNO5Xgfrui2cxGVhOsrwb5fPuql0GJqQuf3Y fIXATBYaAtcMH8PHc4ZzEc7Qs3wGOA0RfMWGPuvy0vGOUql+dkVLwutOvsEgYxae YZ0H8DtiWiIoEpW7bldPy186b68D9ivvnbv8fUXUtmQ+BTFj+nqxzuadTaNm6xki x7ISLfYbUeVZM7CpMTH3GNc9Pm7V1DXZ4p69lW6Cdn08e5HRkVhN2l3doz0qV05L MqJf7EExEgGfrkU+Gp6SG29jQcFkumZoJskafCfvfyi3Abp7kF6yiB3LxzmB1Uvo voghmDYbf037vWqIKwmWZbH382OBpBCAg1zmn3LKhPIIqkqboQ5mvEBE8xQjUPXC wWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKq yzJDYwBS2QUCYzeDBwUJDw0TngAKCRCqyzJDYwBS2e+1DqCYo9mV9ZkbTyDVr2h3 W5DNmwq9Xre88ItDXJ1DQbxnJ5ikwB0M6O2e6EV60xUmsagePZbrQ6t5eFQHOTvE IMTvibHAG2bzndIQ/fzHwjigq/gHacxN7XKeTkZUcx07mPGM/6CkQFV770p8qaQq nPjHNy8YajHMUns/wQT5uDCORlLI96DFiWCbnxP4jPsoOg5pupuG04i9pMxtRdin fgzo4UiiCx9neptD/XbFzuGnC+6Ffb+YKurkJR2LBrJArb33okskd0LgftJva62I D0Kvy49xAcnq5/HiMP6SfIZU1IbNsXcmoS7eRGGREl0Sj7qSDsAtPDXkpNiOGt1c wBGlgEdayuD+C6+7m77u17hR/cAj/2bp2k5YTQae7BfIIyTvOVGSZluINhOljXmh BA9qz3x7eWgRY+UnWOxaj55TQANqZUUlfvju3GRe5dgewKYd8Bk7rOuJYBLibw/j phbX5TA4RKyfUPyEUNxyZl07ajlgcFGhM93hLKO+TlJAuvgoH/MFSiUK5OzI3wy6 R9pH6NYKm805dvj5tT2LZaINriVpaiWPCfRdq43Hxe6ceIUbbLxfH4tAQ/rAuwX/ elAW5peXC556zEyhBxNcJ3gOW/bo55jCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJ CAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCYkZAkAUJDhvRJwAKCRCq yzJDYwBS2UKJDp4u+gHgK6Ygso4vMHWVwmAAhLZz9dRrec4w9bD1t8b7DPfhCnlD Ia02mqI6Gbk5VLe5a5NIJp0DuXMB2OdhZg4OMR5iqA+sWdo4E+m27OhQv4P6myni gNbujkot9RIFGjb3lBfmHaEYtd+GYVyDrpxv4C5Z+LXfTvsuUZ8+vKUbNYtX9oIg X3jGKLgAyHEfjm5oCn7PyAnGi8IVYS4pbJZ11qyQoiv2mlKMs6kHZNE/ECOleI4U n+OWwwOHLNL0vcW0otSlt9awTeLn6PBnz0e428FihdXspVGXpSH/ulnU7CcINd/i WrGljw7FRV4WbkBRt7TMONqLOYMDYdMF5K68LGbjw9tR9Fw4f2coAHhJNCPtOFDX mO04IkEbLh5nbPDi/B/g/C9C2w86ubID3nuHEX1NixjGrgrtAZOwDl6Wy7MzMJ3y 7Z4GD9SXce+qS8XIXYIwWK95qoBKEiBI2b8dw2qWjZyI6wIQBIqi01w10f9d21An TzXpns4Zjux53X0FH4+V2uQJayadKJ29eKvcI5DkNYp02Zg0F5gKSdAtLw1p3TJK jGkKY9wuwKU2pAt0whdkWKKuLuJd+kuFql7uAyyveOqVNyhRCDhdxHA3BBeq2hnC wWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKq yzJDYwBS2QUCYVZPtwUJDSvgTQAKCRCqyzJDYwBS2X/ADp97MQxWRug+QzY94Yuu XI9q8RTzep0hZBuljoFAFiToL4SzOA95epUxsXsxRCp+KN5yAgL5RN1Om2x8RULZ iIEYlFXaUi8Zof958+fyLBHYAiBIYvqMPL7pKmRLgrL9wpI91gNU9BrrtWuBabp+ T+/1PdEgFP4wQ+tkl0nN9RS49KEraHExE1lDNiKeayaYHVL/Q9MQ98ds6X0mN/jC 2p+NEX/JD9VZzwhukzIG+pXbf/XXJSF35jWnaE79nTH3pzY1cRxTx8bjuQNr4xEn Xl6t2qKyTxsgre45JjQ6pAwzyDFi1jON3wceGGIVUU2+/bD29jEJnQQ9He018m+U 99J1h/HHemuj8dgD4sDFQm0t/TRM/ll5BwOKfX4vsptoUSFxaMFaKqGr+nilS4Wf LvZevX8o7lKn2YKN5v6i14aBMgMG/giycTqXyOpc5r0SShRhl/nv7wQuZRw6Eq2+ WJjAHTv1z6k6Xws1H5M4ZzDzUvaD+KD5AppuhSN4b6xyGa/Uh/lKCe7UFRb4GWRO fpWwdl7aSEK4/9JmHn3wxh3wHba4rM3Lm19cpfmfufD+bTjrj9hkmcoKLg7DRRJQ /uJ5L1aCYPlPDXSZLB3OG/Hl3GiaOFXCwWUEEwEKADsCGwMICwkIBw0MCwoFFQoJ CAsCHgECF4AWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCYGUNRQUJDDqdnQAKCRCq yzJDYwBS2RPgDpkBfLeL6EOQuR54r4KokmwVkppUPhTnSvD2vYHD9JVWlhtMWCQl pHxLSe8bIY9DLJl6rihvevf6tK0NeLQtog9ZVhKOrAlmQjx/Hzzw25GeTdJQhoIE xKzZ+AtxpAjn7I2V3F4Gk39RALswvBTlJryjWjS9oVOSiwiYTCyVrT3br9ftVOog j21/D+KRmRI9r3x+V4A2fLIV651iL5bXrwmXHNFscCvG9MCiftTZiK3AGk81U5yV o27MylQk6ujAhcMmGvWYToKVi55+SYWG1+EjCjSTPFckqaw0U7/Cl6sI419e9ssO 8GaxEGkQam6PpS6C+KK7UfeNLWYMCe1kqnDLZ0Wcd+wJD2NNN9WCs11+EZXIykDn Jrg4SLnHrTbLAZ+k8Iomym8jgV3e7ylM+HFXugk39/rSzguhIE00gBUb+b8Zo+i2 5RSIgeiTwT7rqRy6rlpYVm874AogUXqjrWueJcnzqoJDqHsxrD/OSFMzmp4UAW3P BWcPI3DGekxTu3iICcuUO8AuH/GbjgjUu/YV0A5S373L2O05NWwqoSP2QDwkGe+U b8hzp+ENsJe/x1mpN6N+GaCmg5lBsIypAmwdgW4refw5NFNdAIWbv984H8JEJbvC wWUEEwEKADsCGwMICwkIBw0MCwoFFQoJCAsCHgECF4AWIQSPF3dxGKM92pukjmKq yzJDYwBS2QUCXLCIzQUJC09U0QAKCRCqyzJDYwBS2W5NDp0Uzc7YDw0nP1HWoa+x Z/cJXKJmsDmiTf6G9WwF93tL5rFYiPJqPly0prBpWL5CwcRh1aRFhbweAe22SSPw NFh5EpjmuW9lonQUbCPnKSNPNMFjiOtB6VHkXYbuIGfWfWy9XQfEku1uX8DxvY37 T8L9ebvNo9sRPK56XlabeHzRdBfxbNVGomY7kPpcPX9pknsI/K6OyHavKvZV7382 gmBSgJQE7B272/qfOXEmi9xDaZahA9uHGrorv+h31WJ4dTZI2sdRW/W0hjks8bwg AoyG8DbDTDRcLkffPE0euc99M5zc13DhyLYmjFgxJwqdF3DZ+DDtv338FyLgV1Ml Y+DkLY+3TBYyI7TsnH+Gbz4Asc76KvLlzgAiMjxWjWImiQ8wiLDdz6MQ44hCMRco LkNXX+aqKMIfxjDx6IxiGK9h94pjfLwS9m883CsIvcmQzZ+Z2357dV3sc6gUn158 OmM5bbTI1oMjHEkkvyp3Z/hYPoGygaNf27IamBrG9tcITDM9i1AgfACHlPr7Ot5q Iu/WDPcD/9znKEqWBvXsh6r5Qij4b62mVLPfaHelmM25QizNMzQPTXNA0tTA2eU8 AvQurwBN6/J1TVuJO5n3xuBhpmBn91HCwWUEEwEKADsWIQSPF3dxGKM92pukjmKq yzJDYwBS2QUCWjzjIAIbAwUJB4VMEggLCQgHDQwLCgUVCgkICwIeAQIXgAAKCRCq yzJDYwBS2XkUDp9QLXbWzqYIvZYm0Mq+HEgHr0VpRmRuNp9tWqhFEw8jSAccIv4A UzDti1LCpPZPFstg9z/ttT6lYB7VhPqmTQ4tmG5HPIbdS5loxUUdynbqws+sZE6B 2jhHv0xRQMwtiS5gpFxOt2Lhtx5mWYikl5S35JjzNwA/ebh6l4Q67e+skRHXGCUW Z40MRyMPfaJMkeWQZzIfD41aGXqXwu8Wi/hlXJbileJiOeNs4ery6Rs8gM95p8yS KyEbXx6QQsaga4ukOqc9gb0BheLLTcPpnB24sjvvRsyQbnOErMOSwgZDzHQlQ++2 uhKWA1DB7U8WUNLtzZsizcmrAKm4kKUQSoqS+DuxqYpdY0I7be+X25yY7CTEybbD i/T1aigWUbbyFKwf4Uv5E4RTY/HUwltRqFF5NuyGjzbw2y2pnjpRaZxZ72r1gPCc cGPawoTLjt/aZndmhHXByFEjHN7t1w8tRM8ygTKMAUrOyijOkT4CH+FTAiM9IQrS R89pDHiNH1AoLBOcysc2zXqdVQz3OFcs2XBvat0bpjR0DIGWUu8ThQcAXzHca//o 7fEL89TousBSK0fSZWJX4YcefeNZXug7c2ZXbvH5XDUOpk71dkw+qaBGhHMwRBfN JE5lYWwgSC4gV2FsZmllbGQgPG5lYWxAd2FsZmllbGQub3JnPsLBaAQTAQoAPgIb AwgLCQgHDQwLCgUVCgkICwIeAQIXgAIZARYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZ BQJoPu+XBQkU/IguAAoJEKrLMkNjAFLZ86MOn0bYAE/UQDl1qMoz2QxC4Q0LSNkx MawPl9LAgrYRagrlQhHzCvuyKdETrEuNHjFWWkKZvy7q9TeqOWI4d2wbxdUfgcV5 dQ2x2OyzqAqReWKSMv4sB8p0oquFxbWgMqWuAq0e+bhF9lfK7pshTclzMhasv/zm UCDSHG8ZApSxYgV5NMbfSPd5DiY7jXDcX2/sJRoxs8QGYGaOtMraRqao9/JEb7yO BiyUcfYcv3WYIuDekIQ1g6AngfEvS9RNDtJ3jpPgQYGu9x6lYDA5O1n57QZIMKu0 nVJFAOWI9+OAc4nRkD9rED9Hox8yQXdjXweyqPkLh74kHOVvGuTdFE0GzWIpAQuf 878/Sd5BpKyYW7jSMNym7CgR/t+1bVyoh7HPEY7lRF4ctBw0xu0tu1h21bLfZqLL wet2cGa1wqxb6Wd0Lq4JpYeU3gYdtWCpvYR1y1g/45A/26/TyVDliN4PV8cy8cRe GCeo+lORGOkc+QQupeLQIJZm2VyvfFZ4s1YkscK26qcF8ozlUCw1nZZhu2jn4+Nz ybkM9lrhY9Qw357evxrUEuxuV4SQK8JcXV3L7g/ZVhGt3cZBzKBfs3nwZQGesSuw sgFU+BKoGP5EUI1/Psknv8LBaAQTAQoAPgIbAwgLCQgHDQwLCgUVCgkICwIeAQIX gAIZARYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJmzCmkBQkTDIO7AAoJEKrLMkNj AFLZ9HkOn1p4xeT4g8+FswnDWuz+kgqkw79X3xxim0VWW74bNy36K9bPoZ5+Dm0I U9BeHbZJ6OtNkbdbpbWhZcJZ3Hj2f5vpZiZqGYG91aUkrLys40AbX824IawAVVrA u7/neEFKgC/Nh76aILZglI2183O/U3GOZir+JhVmnDJ7VzLXLu2i/lb/I7mhNFiD ZUrSTH4/Ri+ByPsWFNcBNifwTDoIKoFBqTmHRAOSmJBe9GNZ6sQNOpVddNMORVhr IX0BOUDPoP//0GnMZjvkNVz+22PhpXdsnpfqJbKqTuYYQZqt3J2Njt0tmeTDMoMy +0Zm8t8ILGEhafZyacWZ8r5UUQq+wlXVhXAdCiIgUfy3euKP7rWSEDSoZvv7CwsR mwxRv2Zg8tu4kXFl9CDKKk6m4aZXOLNU758SDnNxZT5SzLL8Cul426CwP1XsfrFT Dx25gWoUT547AV0HP0Ag0qPejxW/l1WH/Q0kXk99EOyHOdsTqyJY+Tl8c+G+lpvv 4/1It1fEok0CxZnLaFFqaUz5CH3RRP48HcYV7tV68zsfEs3Pfn/xu4LnIBnIBQea FSuil6GOL+8yUQMYCDczfKQZBxMChCyqekG75hbihxdhjKG18Z1oF2OpoMLBaAQT AQoAPgIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgAIZARYhBI8Xd3EYoz3am6SOYqrL MkNjAFLZBQJl3aSeBQkRp1e1AAoJEKrLMkNjAFLZP+EOnAw9drSqLDdY2Ik7fFl6 JqT7l+YyZJR77MNnM/dyjxwmqmqU1tkDgrSZe8T4Vf9cnDrHXh7kxyXh3BMigfbQ HJPRra4nRth9ZFdXQ6G2UdmZ1afGlTzndNjmaIaDqW9aotWinivr9P0aMyFaCYBf /gF7dc9rQ46AWXjJrJS8eYU5rLs7wh4Lokx+CLU9nJ/UHHc14nhQ//TYLMCEirSM 0EI82D3FAtSrp2j9T1RH07jTTTHlOwKX/rIEF8dhSGHAk9EDVVujRiHECi7lRUiH 94/rZCpHaSvExMoWMgSVBomwq0zvbuC8wa+nornr+67YsOs4VF7k3j57gT78UH52 VAx6cR+BBMx9QuX8FjcjzNZ9zQaUZ5lVICnSEdD/8044Cm1G3u3+ZN2hCMLFxbOG YDWMZynxt/zKvVkS34do+nMPAApH4udlPbxm6UDopmub/oWqUaIS74mj/FI065xH 4RuQAUWi7wt58XaYVRVhEZbafbcTFz7oIFfv+iRuF5C+R7BeJpwnRJYitIyxmX4X Xg/NvbdmI3f2ySLsfyd12my6HOYb18d1r0QGqjI7Uoz8SRXlUDyCTKHFRmEcuxtq 59wZ01jiCa0dQwlVRlCBQqbsNu30tcLBaAQTAQoAPgIbAwgLCQgHDQwLCgUVCgkI CwIeAQIXgAIZARYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJkJqseBQkQ5EO1AAoJ EKrLMkNjAFLZgtoOnR8xmvB8saoLwsmJF8j4fBX7b0TsRZomY4XpLbix7CvW3//Z XPiZzjUTpsOmsewe17gkSbPIKdedeU9qhvI41ZQhthyczzvbebImaXQO7gS++8k9 SJ4yLAVbNF2YXFz95D7pp5NNSSc0kpWFjXz+qwCm9hMiS+aV4+AtBUa+mdipDUSW Ax/vrwonj6VUyYhPb58eUt7lHIlGVlyNWvJXkf187L5NCqEsuhMWHECIkEAJghQK CUaCNNB6OK9ddFeOG8ym+UHNLHAj2JkZlQvgUTWSMr316miJy032K/U7ldNlhOqR 0F/U8Pv0aJwcBsboijwXTvFH8KKNmXbuXqstvnn3/fcizCLoxryZ2eZ5MnV36Kj1 du0AaE9morEzZe0ptU7y4mWLpgKp4SlU/79bLZyDhFKPjZvnKumVupW+dt13Hxlg KblJcPo9v9mutSYqVrK4zZScyz36ycgYb9IxFS9vHY6rp6qv1Dvha79YtrcPITRR TiuITvgwfk4uLNZLa1ZMec3GWpStO1avMrGdMLZuslkq1Z50XhItWljV+SpSgHyY zZsA8C5QA/BgHWNCZUYLtUtz9/Zr0pkDeFCIIDFKfr1q6T0VkY9C0FYubklFtnbF ocLBaAQTAQoAPgIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgAIZARYhBI8Xd3EYoz3a m6SOYqrLMkNjAFLZBQJjN4MHBQkPDROeAAoJEKrLMkNjAFLZxKsOn0R9ommmBh85 jdn2+05r0oDthUZpRQAEAV6mzkGzPWERJA210Hy5ierwYzQypAscmqVeL4hW331W xu16a8UUF9lR/KPp2pS0wey+9TrDLYpGRb27iTKml3wEKzOOt9RdgN/CcTVGnsTZ ukNMEJKV+gBaBVPd7r3V28De7GDf2m5tgv++Cyg0G08JxXV8omGbIjk/ZGQsNyBS i3OfQppA9XWx75WmcBSjI9S9iGL+NxpTq4EP6unaDWir9mCryMBLHVdG5RhrwVB1 CCwDxaQ7RyaFbo/Ws/GpLjbJuGnGJtTUoEzcpy5g6ohi7Fia3b4rIXJIRkHe1q/j qJ2CAA7+RIAg/RjKNaAbjJCpZP4XnRwEW9stIOPOcCdu1HG9NAkK0rdEjoByDtvi kaWqi1bneHC2CJbRuFDIrBTxnhV19+U7p2RSM3xZ1T4pW5jk9SnBh3EYOf114S4n rRVsuwr9j35eupAWNf1l28P6+fTRomuU2cAoOgX30P8LjmmuznTer0avTg4JEpJm eCBDNs8edrhYm5kZ5ph1SPMNftPMlWHMnSK1Aldn5QzNTK4lSMXB1DATJAMyFMDD suS2GfQ5DwiVDVEdMPi4WciAce36SpC2tJzZeMLBaAQTAQoAPgIbAwgLCQgHDQwL CgUVCgkICwIeAQIXgAIZARYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJiRkCQBQkO G9EnAAoJEKrLMkNjAFLZYZ0On2UvYdjhAsLQZcb0K9EWVrEIp7kUS0u0C2LTioCI kb32ye9aRYMoauJgil13975W9TL7/AEXSc5Qg/QgFua187ELqCsCslckS4OQLdub lOrpVX0kKAhM+W7rxJuobDOTSHGBloW56OU9tGxSkwpm/ESTR7Zv7gJDJC/GlBCe 2bl6rw8ykWwQiIhfvIOsgfE5ojp8JjktgvpB7IUyzstvC65ejr16PsoDeGdju0OT oDGagxlplIZ5r6MlcmPc4e7cTCh62ZT4o5FR52afcTx9MqR8TEc1Ij5MyQurQtqw /zS7qMAjeu8xaVCcFmQHvr/Z2ZjepL36O4cN1Up3boByGTH+oHpaL9WdTsM4n5Zr 2sMwhevI308UYwt2/ROEOHpbLv7uc45X775BUQAmNSgcLUhteqddIILz0lVBbmsV 1CIeZiEO+Pz6se434EKaUGIIlYqE7Oqf1tLOYm9knpyYtB/CqK+dyzz2od7QKez8 B7e8yx7Ps1yj9KzeAQb5nHnpEekkwG/5TpLMWGqN33fgeJcZtR1PM3atN/6UIOU8 j4z47S5dC/hsCVGmsSxysARY119AqUZYUz/f+97+yD51eP3nknfyPn789A1JkcXg Iktl1scMkMLBaAQTAQoAPgIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgAIZARYhBI8X d3EYoz3am6SOYqrLMkNjAFLZBQJhVk+2BQkNK+BNAAoJEKrLMkNjAFLZKOcOnRG6 kdoBqmizCtc6UmEtzBIHSjS0TyM36pYbVdOggGKYsV95pEDXDDsXcrHCzIY9ZM++ ToTAKcx3Y53SZTFC57YtJbVwV/Vc1xZJV7R816BPOxXaPTtegu+3Yd94ckmck9SS 8rLtyJxn7sK/EDeDyG8upg4PIi73o23Tl/ZwITu8Rhfyz2AY01Ub2CbRyI6ePPM3 Lj/o7tGocYNCaF52kMUOvA2jCNel3lXaEfpBx2Qbt1POlCEdLa/+pJGrB/e3QpmN 7ozc3ysVs3fTPhvL5FOwUf9fspceTwNICAI8J/ZLObOeuNv8LAd146lP/GMLYzOY 7oivcFeJenE1GQubZVq1KpBrKKbkpnOJeF8bi48a2MlyGTYKU7KNPFgxVDc9dBI6 GauG3XZEN6dI4HVIkIDK2phsu8ENsNEE6Ze0F7I9EAbQPA0ytvYqRWRNjVeEA1XJ 58y1mjLoM8EWv8r9SjGWLyc1I/AX6F37uZptlo1EsiAYOLjgWt42/Q1tUTJFX7Dk hIazgaATrv3DnoencvJy81FGfgrcvaulkQBCsl3Zt1SyxorKd+xfTglRr6m5sHX1 bKqicEX03fjavkkowOeOAZGmLJVhpUYMFgLYNCwW2AW30MLBaAQTAQoAPgIbAwgL CQgHDQwLCgUVCgkICwIeAQIXgAIZARYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJg ZQ0GBQkMOp2dAAoJEKrLMkNjAFLZwBoOn1QierIhr15SUjmIttoxEe7EOaXd7WHy JVfnkpbggwbfHyl9/DiElK//ZAPmYqp7E1EnFbGal6qusf47Vqv0B4zKm5YjKadc 6B7rIUrAaXeenqqrsWgTw+gAGA0YgITLHEtH5Doy8TBxlOOveVz3EqjgvjGTLk2Z U+kcRjAfOSpo+xi6cJ7KJjdvMSU4Q7trFknF9TNDFkQzUG6rZblXB6rAivvFYgCK jy2MGqxWqAFzZ8N++jC/cyDaaTBlQgvDF+dxHfMuof8p5UKp8zfa/4SuBVLKue1j D+f9LJzpPwHBtqa/EtBUx1etbAjqflBUKdrHZ+vmNO35bb6swqJg5crDwIddXEaI nw+JOPFhPHSRRl76KHvU/yAHCW2LrUyGmmYrgGEIW/s7wVP/V+WCLUaT4WF4Hizx eibRaQUcnXbc2Stuwmm32YEHW2upa3H7+TH148EAx2KORyVaOgYtS8heFFpiqUGw GLD/CAPRP3MvcySSCZpFulsYWs4uvO6lsnjEZ5g1ZxEbxpaJ4cxMeIx1OyZieYHv eAQx/PWx/4t64UcK6jHpMs4zYsPFG3xzhLRJCCm4FJPeyGCGq+nhqrCAyTQJpBeQ adyCmXQKsb/ICx1jUsLBaAQTAQoAPgIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgAIZ ARYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJcsIi6BQkLT1TRAAoJEKrLMkNjAFLZ 76YOnA5g0BjPqLGeKhfEdntDVCs6Yt2bubYvXnnt11JlCmH8A+DKdcabnPpphrHP OrdBGlstm/+KhVJ2otV0y7LpZ0mid+foX/nc1YVjqLCTeIDKO+ES6Yt7/08e/vnQ KPgBxlF6qGsUsH6ckdBSzRJIInrFNziBbiHqdKJFw93vYVTJ9m5IGP8bRJ3lsS7l Oy63DEHMJDXqk9q6+Y7yVqz2+wH4lhgJ0KJllYqQGT/0Vv2od47cjRSimCbLIb3W JnbGdSufXtUKKriz272eNGC9RNQ7mYxqvm+XWiMUzXeDEaegaUP5BGPsTGu6hRjZ YHKjbcAyApYmk/8OUvK2f0FJaZHRsIpDsv2WBQAKXwkgap1nm3PiYfSS0daP9Kob TzP2m+lr/r4d5uixDLryiWnUK2jCAxONuy2gNwd0rRJxMesOS/1kV9Kop4xIpGdx /wzTh86fq2bDRmZKpv2NdZkNR+gOPd7VwZyJmVNoAINKP/MN48o2w+j8xVRhVkJU /SpqOXL7pyR8dUcnL9lyS4Z8rxeuk+uHXypa2TGlsWn0judK0PkLSLfdZdmXqWHP dmfFK8sHMt72+I4RtaD0Xrd+2f2U5j5EnQjQRjbFhsPVnPZYjyCnR8LBaAQTAQoA PgIbAwgLCQgHDQwLCgUVCgkICwIeAQIXgAIZARYhBI8Xd3EYoz3am6SOYqrLMkNj AFLZBQJZzTZ7BQkHhUwSAAoJEKrLMkNjAFLZg9gOoJauK/dNNH+tyzxaiExoDTQ8 QW77GrVx3XQMwqxg3iOZ2T7ekh09gQeX/4j+Lv/XI9Co1Aj3dw8zfLnVt+f2pvHi QbnWCTTRIuNv4ymcEZUTV2xZ1m7U8iEKbsddYBHHdHHYgPATs8U/S2pUU6/WSx6b hI1jtjq4WI4fFDj1TCf+OkCQ6ygAYSc8tqPlIaIJr6yFa7v3T+9Dh/+/S+GpWnoI lcFbAqFvNOYp9VNnrlvL1YZ2BXGKQNIAD1CJ+1ZtUgHb5RtiSphsoGVX8kegOY9x pGRFVJQ17pqODE7VEh8QbNgcPPAb15xAKYdz3fj0sfMVe+r6fl3lWzQCrRLvwZ8R 0MtS1cmS0pjS4d4MC71kkH4qSUwjhWA9FzEvP8tsH5mnHaPFBsi0J4/XN+JBuVEN 7zD+wRLrHhSRB/+3SGHdkrN2JqFlWNqYNoOiSng7/vAfdLq6L4WEaawuT4dYv69Y oyDtIrMtAnDz8TeBrmzteTApqCaTuC3/YT68QGoKUVzd5asJMa+0kwBe0L5lrVOd PIwO+3T2nDmBgOFZyCFRrwZpCvdvH8volakM/dtwP591ZYhvg235h8lewnstynZN 4pAmmJj1uNXhSERM2X6z5/CqT8LBaAQTAQoAJwIbAwUJEswDAAgLCQgHDQwLCgUV CgkICwIeAQIXgAUCVSOlpAIZAQAhCRCqyzJDYwBS2RYhBI8Xd3EYoz3am6SOYqrL MkNjAFLZ9PcOn0Hm3hibYknfxnru43LdXA0osBOBevQp7jHa2eXlubj736z73goN 5x2lfDuL3+VT8dUpfsVkwBxVczih7JB42GeNQVe9IvIODdgsj4zpguVlhkBVIen9 SzDl9l/tmbTbF6KA9Ja1B0LDs3YmzTmJg+B0QTBSxZrbwOuu3xyMCxDJNklHwNJn Z8CM/pu1Pi229rjTWOWSTrc7SYgrsmlqGUauwbyPrR2bYPoMZhOSEn1NGJYTh1L9 4M59ZuY5GTmDTab2jTCwIE15gcmMl3XHCikCQHgZgVGkxpcu5qtsL0KeUIEKc+h1 ifL0nwmt/FPpjryOrgMQmFk8cv0JWzGSa5GPBZ9A8ava4ZdtFTSv2c00oOKGhjk6 LhE5DbDroGdGf4N3XSs2k0IjBD7NxiQeAxvAdPSkaPZAwINOLWD6INzGZ0Jy+2On t3cupETR6JZLhUl+k9LTYdp9vJDSyDcxRQQMeR4rD44MclJcxikTlJ9Aq8v6t7E4 vgY/gAxDYo5slzc8g/GUM4+xsuD300voX82t4kiw2VqZ2PEFc4IUpRaJlAO1ROpe MnG76XqbqfloQ1gxCpDaaf31DeXECr5EC3iu0P0NJ91rUY039IOHjRTX9UQJCsLB ZQQTAQoAJAUCVSOa6QIbAwUJEswDAAgLCQgHDQwLCgUVCgkICwIeAQIXgAAhCRCq yzJDYwBS2RYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZvZsOoKjvoLatMgPVKXFFLZis 08PVqEruJkUFY7RVR8Dsf7exCDt9t5IEwqoi66aC3gkaDRwCNq1sBLCI8vxklE0u bU5fqvpjN5Az903U+xwYTFupqQASh8ARybHpAB6UBn2Q+aHUZoJGq76drO8HVMcJ lC+R5KsQDN8YSTAdc7uST6PXYi5KW1BgKh+owr3B2KmacxG7GPDog9SPIvp/MJrc SnR2+SX5oO+oUCFpUDU73Mkqp8dxhoczm1176T8I82S4yJGJlIqGGSlaRM5l+ttw 0llZRNlORb1GXqMo13Ka7cYLeLA39SIOAPCh7c17Z06SSG2VhzaUTeqidE9Jz96Y 9vaW++v6tW03qC9hqu7ThFN1PRQCoOpqzKpepdeLBUdnW1TWOmGhxKN4M3K1ZmI4 EG/bytBNhrRTfni3eg3ak2i3dYuOHtMzLaSLAF7EFflmik1OVeNCRTCYJ46sYBnp fQCeRNgTViiMJ+mCFcTxf6IHyl3uKPDOFQExnvjINxgP3ouaEPNQiA2EYBoi+xYe XYM9KXZ55RC1Z1PZCfdmaDTcvMJ4qLP1OVrzwj8RwhrL4ZUpILx84T54PaJquj6B jgEPd0To5ILPR+zc8Qmx4iWcTUR5f87ATQRVI6aWAQgApzVRJF/utO+M73xwoHzr okN49VSBcxkBHh7G6GxzX6N5DvBBhkh4mGVZ81q4dlMFMtpq1xBb17Hgw5iWmjv4 Px/2rAeCfOzk1zSC4OMl5Lby36/CmiDjcJGqgR0tqXiJif4B82MBgJINibabiGG+ +iHQm9kmkWSVquAMsq7YIyTdgAdbuSd5BVih1hjqzBrB7AMyfRzDSCaIDM/ztKjb qDnsD/c9tFvMQFMMSYzGfkcdUD3HTLBxye1XD5Iav9AGP5KNMuYko2M/cnKemxl3 KIZlpcZR+aErj5U5XaOhOt+kuAUwC6RcLtPK4YhOA5tCTe9lHODdbk/k7BGXXeSQ VQARAQABwsJvBBgBCgAmAhsCFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmg+78gF CRT8fLIBKQkQqssyQ2MAUtnAXSAEGQEKAAYFAlUjppYACgkQciO1ZnjgJSimlAf/ eQTOhj7aSKAgiMYK3JaMXd5Xa8YHPi1OJKzeYLWEJDQ4/2LW6Ke2r0a36bTkuVJM W4q73VDRjcCsIMA0BtqAOZLtFVKFsg2E9lfsjcIX87z1NvcMoNMJ1oOG546uZOkp fonb1zajlMNtUiMZyNUyy9BDIz+jr/LsNc/wF2TIj97B2wS3y6T1PhWllMFXWKDj 33zRjNFrKSlgWg6fQv4xdx//yiQCmO0x6FEjM1F6NhPfTfDVHxd9AgoNZFEYPBBc 715VJqLD5nYRsTihE6RjkiZqUP6wrgViezGcrjDc7vh8aVgJ3dDZwCNJJ/JUSpyP K5SiDpaByZZ4ozEJMtmk7/ySDp4yKg+YTwmnkwW2cwYyX6bjqStiXq9j1+Vt4a5S 8t1hseJuKKi2eI0uypOaP+viBZukbYt4VWcMJ84zPRSAtdeBO4/4fdinHzVij98G v6b/4KVs9IE0aj3Ow/QakE/sf4nye7PWRFMH4hCVafkFnsYTZqMz62EZlLxAd2nE YfxtVoMM3MtP7AFy3U21AyUnoiddrfw8AkYVp3PEQajvEB4aXM+YaADmwncVLu/F Bn9EGCCTejFD12WyTTidiXcCnTDwQ7+K2jTs7kqLEVxga5M3Wbrgp3TwXSs2nbeu +vAuVSMuZ3mdSQI4LWnPpmc9kjbVCrtfAfZFJOZspLgUqTij2DKlxjbCVbjInyFA feBiX5YP6IZeY+wySLBoBZoEH5eMdf93FnV9OXARzotjVrE2r2eSYN++bJk6PA8y PJXtLC9CgycrnWHOqpmpM7Wo6fmvb32C83TbkUah1qWN+Wkc1hOiY48f1nCPvRU3 8y1KcqSlkLyebbWLOWrHEKMjVitBWiA4OFL+YG67OykFTqEUkutK1oUcNwV5QsXY lEsroiRbd4YvGCNzcUAALzvZsptvm44QiVD9iYgeGxpItXjVzDIcqmnoGWiBkHu4 a6NMulCEs4/CwmkEGAEKACACGwIWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCZswq CgEpCRCqyzJDYwBS2cBdIAQZAQoABgUCVSOmlgAKCRByI7VmeOAlKKaUB/95BM6G PtpIoCCIxgrcloxd3ldrxgc+LU4krN5gtYQkNDj/Ytbop7avRrfptOS5Ukxbirvd UNGNwKwgwDQG2oA5ku0VUoWyDYT2V+yNwhfzvPU29wyg0wnWg4bnjq5k6Sl+idvX NqOUw21SIxnI1TLL0EMjP6Ov8uw1z/AXZMiP3sHbBLfLpPU+FaWUwVdYoOPffNGM 0WspKWBaDp9C/jF3H//KJAKY7THoUSMzUXo2E99N8NUfF30CCg1kURg8EFzvXlUm osPmdhGxOKETpGOSJmpQ/rCuBWJ7MZyuMNzu+HxpWAnd0NnAI0kn8lRKnI8rlKIO loHJlnijMQky2aTvdkkOoJ80A3rZBsdstzkg4/OsXzzxQrI82QoUs1BPWa20UJRi sxHiiyXBAQ5OyHi2xEl5ZBV6KPTQrfTLHle84p+k3RCErKoFSu5iOWaKJIvZEDM6 d3jCyDfyheLKWWEy4f06uDtGjDmPSM2jivnGz2IHJ09VwwC/VQAbr3Y1jAFKeO12 ILBx+OzzZvMHz2aaFF7zJZbPuNZQ2rr2Falq40aMt07Fn8vTDCMUAjcKBOdlDgkA vKX+QCu0s/eXBK0SRpyHMR8LgSjoVhcLK1Q11wKf3SUWiP0+nBzbZ7WA5cltw7ip EvhNbgTWl5/LhVgrHfC/8UBF6qmHz/C3Wo5Uc/9ynFZQGR0BlfwNxU25IQFdeHvV 06cIxKYI/pM7fw8vy7cJaeQ0SRPYE6YUdGlidQzf8YhbO87FNqd+AgplBSJ5isZA rYpDJNAfcSgH5EhoGCYVk1z//6BZUedFOhOit17LzRrdEZ7B0x5A2cv3nb1KVpRg qPj6viF6uCt3YxAPLpExhWMonO5SePSF3i2GxpvQZ/h9vV/XxGpivj2KvhaWrOmU GDJzxxof14Ns5j4X7yhd5YoveB3P7CeYfQWCMTieI3Zh5wHwOXx5os1mbWTeAaqm nnO6xsLCbwQYAQoAJgIbAhYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJl3aS+BQkR p0woASkJEKrLMkNjAFLZwF0gBBkBCgAGBQJVI6aWAAoJEHIjtWZ44CUoppQH/3kE zoY+2kigIIjGCtyWjF3eV2vGBz4tTiSs3mC1hCQ0OP9i1uintq9Gt+m05LlSTFuK u91Q0Y3ArCDANAbagDmS7RVShbINhPZX7I3CF/O89Tb3DKDTCdaDhueOrmTpKX6J 29c2o5TDbVIjGcjVMsvQQyM/o6/y7DXP8BdkyI/ewdsEt8uk9T4VpZTBV1ig4998 0YzRaykpYFoOn0L+MXcf/8okApjtMehRIzNRejYT303w1R8XfQIKDWRRGDwQXO9e VSaiw+Z2EbE4oROkY5ImalD+sK4FYnsxnK4w3O74fGlYCd3Q2cAjSSfyVEqcjyuU og6WgcmWeKMxCTLZpO+0cA6ff+ngQvCXy5w7chZDslpe6843hSZIpFm4wOS2rpj/ TJBDwAa5FLOSdpNUx9GkwPUBWe6w6yHkEZDtGEDv/LNEy0+XPNK9WSv1NJJ1qZnc S696cBYS0DWe93+79/OUXI08bPv0glZB1yoilfWCL/LYCL6rtTte0IjQn9py63gg PmgCuoLcVDzkSGKmog78cJIBRJSDUApL8dzOxJWTiX3WC3GLmXHJ7/vFg7AJBE97 0LIkZDESDfJ4uDA5SGYJPGnhup8IjNZuO3HyD/FQV19IqtcrJLUBEWjtaPTF6lLO dQtMQT5fd58jGyI7vt9Ehi7znYfEE0NEIFQCcXMg6+PRANqnLBxvMhtQESZNhXHG XxPkRv7BP0wUzvZqJbl2Ap66vq0NrasdsEiUzPBhKri+NNFSAI3ZWrRL4e6rJ1yg HRm8KqU1XUVRKZXl64MS9xGQpsWsWSwOWr5oBiG1m0gj25R0fmj52pZwxdI4DYF6 f8g0cxQmDOENeXO1daLx23Y8A9H9Zvdbb63uzxZcvCsJIutcygTGqic96aJGejXF cG9icp1gK2nPXIDIz9m9BteNNuBIDLczknLjBwB3Ert9hG49ww2bTZ8mzDPwLDPZ RWYwNQyYwsJvBBgBCgAmAhsCFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkFAmQmqz0F CRDkOCcBKQkQqssyQ2MAUtnAXSAEGQEKAAYFAlUjppYACgkQciO1ZnjgJSimlAf/ eQTOhj7aSKAgiMYK3JaMXd5Xa8YHPi1OJKzeYLWEJDQ4/2LW6Ke2r0a36bTkuVJM W4q73VDRjcCsIMA0BtqAOZLtFVKFsg2E9lfsjcIX87z1NvcMoNMJ1oOG546uZOkp fonb1zajlMNtUiMZyNUyy9BDIz+jr/LsNc/wF2TIj97B2wS3y6T1PhWllMFXWKDj 33zRjNFrKSlgWg6fQv4xdx//yiQCmO0x6FEjM1F6NhPfTfDVHxd9AgoNZFEYPBBc 715VJqLD5nYRsTihE6RjkiZqUP6wrgViezGcrjDc7vh8aVgJ3dDZwCNJJ/JUSpyP K5SiDpaByZZ4ozEJMtmk74O7DqCf//4bVzrgfhCMmTXoYi9SlNhZI1WuEKYjXW9A fvjs3d0KFxKTA+synu9PUfVt6Y7LJkNjd58omZoxYBBsRWKKWYb+mnA7Cm6EEaor qWQWIQ2iwgVyvHF6kh7EG7jbDruTr/oQp25ZhezByoVlIh6Ytr5qR8/5/zFBoNZ5 PfLycaQUwsqpWeQ244CVd0qfnfrSXgW/nkFctNIKMFsm6qjft5Av26ZJRWRLnnFE NcBhzBXXdEnq5G2rbwAT83oLx3p63I/fp0TTcbKtlFhE16Ppm2nRWdHKbb9ZD7pk a9p8ubGUYai9OmZv3RaA10eOialWRY1tkBbWA6N955N3JJoSAv7vaBe7pP3qPHOZ giSYQWWfneST4b1HpZeHi+2NWBu9BmbbBQG4Itg9VtImlAGHJHVhC4h2XKzWWIIA nmoeL1yWl+CxcTCmipWRPk1lFOUS8QW5VBIO+u9BGh5FPvVVNYSa0tK9GF5DrNtF kL/NhzQXA6Uf+2aej/QKp0d4HkG17SXvfykEqLTobHA3vxWpMFnZZhI4/SVfhM3+ KafactySTrJWt3ZuOnfxv3Gfek7QEimOCV7+ylIu/xLZlbBlRw6UHurMKZXpRoYO dl0qOUig0EfCwm8EGAEKACYCGwIWIQSPF3dxGKM92pukjmKqyzJDYwBS2QUCYzeD FwUJDw0IAQEpCRCqyzJDYwBS2cBdIAQZAQoABgUCVSOmlgAKCRByI7VmeOAlKKaU B/95BM6GPtpIoCCIxgrcloxd3ldrxgc+LU4krN5gtYQkNDj/Ytbop7avRrfptOS5 UkxbirvdUNGNwKwgwDQG2oA5ku0VUoWyDYT2V+yNwhfzvPU29wyg0wnWg4bnjq5k 6Sl+idvXNqOUw21SIxnI1TLL0EMjP6Ov8uw1z/AXZMiP3sHbBLfLpPU+FaWUwVdY oOPffNGM0WspKWBaDp9C/jF3H//KJAKY7THoUSMzUXo2E99N8NUfF30CCg1kURg8 EFzvXlUmosPmdhGxOKETpGOSJmpQ/rCuBWJ7MZyuMNzu+HxpWAnd0NnAI0kn8lRK nI8rlKIOloHJlnijMQky2aTvoqkOniNhCrQ9vugGyHKRWrTK8NWAIrEGQeN22IQN EVBlmfEV/O6miL1byeTEH701sbHEYhCjDvda18V8wQlG8+RBnx+BZpqjGyOWbC/8 1JJoYVB4+w0wCzp+6Vg3f6Hl7xN/6k/ebo49F/CxFeGLeyGPYieeytibWtO0jj9U jZXqHliaXQsW++tQfnHfqFcm0qCBaviZKWg+rdIDs6tOdy9OV/r0PQCnp6T2K/ni dNoANbvQ6u7hsH5A9bwSPVm8bPrJZ5827wb3jeJb2LxR6AjjyiGfuAcnvPX2a88c CCMdjalWJ4fIzPblULpNRVzGt2SlAZRfCs/PKxDbGTkbe4aWbxtukrbFu4fJCbyZ 6FDqRQ8qnlsc/n4t6bP4jRixBZl8IWXwl/mDwBVzZvr4S0/IbMc2HXwuuwqXk8dS F72cejETD0q1rf+odld69MSGrZ2UvkjgSiSlJOC8yJU+blECdcuyqSDgTPn6bVU8 OAbFDaGFWZ2cLT3pBiCOpiKd1sgJclZO6sknUmejVnOH8YPqwQMS2BcfxR6jkjGn V8dq0VYwFFq4K13x4Yy3rEmmy5gj8RWWm8UO+jrQCJ0VUSLeBUk9iyLlxL7qTA/X pfwgXPuyEIl6PMLCbwQYAQoAJgIbAhYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZBQJi RkCmBQkOG8WQASkJEKrLMkNjAFLZwF0gBBkBCgAGBQJVI6aWAAoJEHIjtWZ44CUo ppQH/3kEzoY+2kigIIjGCtyWjF3eV2vGBz4tTiSs3mC1hCQ0OP9i1uintq9Gt+m0 5LlSTFuKu91Q0Y3ArCDANAbagDmS7RVShbINhPZX7I3CF/O89Tb3DKDTCdaDhueO rmTpKX6J29c2o5TDbVIjGcjVMsvQQyM/o6/y7DXP8BdkyI/ewdsEt8uk9T4VpZTB V1ig49980YzRaykpYFoOn0L+MXcf/8okApjtMehRIzNRejYT303w1R8XfQIKDWRR GDwQXO9eVSaiw+Z2EbE4oROkY5ImalD+sK4FYnsxnK4w3O74fGlYCd3Q2cAjSSfy VEqcjyuUog6WgcmWeKMxCTLZpO9qHw6dES2t2FRWeltMIX5M8iynSZwSlwm4Q0yq z3wW/xmTeFxSsUEzjc5BQ1HKCfCOR7ERI30FejEU0kPnaXoA4mqykuzqYS+CFTm3 EOmDkRay8aAJgoMg4bSWskceH+PtTluIXz4/ynSMQW/zDPdURLJdVafYj0fgTVKZ dbbRL5Mk+xBQhaMs/LinJSLhIlIgSBEOcKRyee9cAlyfe1hl4kOTrcrM+JqumM24 Z9KtNFy7c900i7hHOiCiBnZElquoBakIOgujACmwLvGtETbX8EYyUQUZ994MWuMU 6RH2dHlRMrK7XuaFajJMXRq7sx9qOZ63ioc8tVWvCJi9p9G4mIiKY2KWjNXsQlR0 C1n1d/eRMJ3wRZiyBNIovo54lxIXHLUwrxbUsDqKRsoX4ivUBi5bCW4ZEy71tp9b PTWj7L42xRNlgAp/wQo/0Cqt2lOj/TKFQ0xTd8BsmRXL3N0LTEntlivpMhdzc1zb Nf/QnAz3+NOUn2ab/Q2IJ9aqzGPdmEaEyQ0QP0/AMeruJp4Oindd6e+qClJFzw7T mADrMXs4imU+zuoszYnxFchbW9sG0sOUZpNyZ9AKVtON/LkS/ATIHXn3kinqPXcl JGOHrNuELTYqkOMbwsJvBBgBCgAmAhsCFiEEjxd3cRijPdqbpI5iqssyQ2MAUtkF AmFWT50FCQ0r1IcBKQkQqssyQ2MAUtnAXSAEGQEKAAYFAlUjppYACgkQciO1Znjg JSimlAf/eQTOhj7aSKAgiMYK3JaMXd5Xa8YHPi1OJKzeYLWEJDQ4/2LW6Ke2r0a3 6bTkuVJMW4q73VDRjcCsIMA0BtqAOZLtFVKFsg2E9lfsjcIX87z1NvcMoNMJ1oOG 546uZOkpfonb1zajlMNtUiMZyNUyy9BDIz+jr/LsNc/wF2TIj97B2wS3y6T1PhWl lMFXWKDj33zRjNFrKSlgWg6fQv4xdx//yiQCmO0x6FEjM1F6NhPfTfDVHxd9AgoN ZFEYPBBc715VJqLD5nYRsTihE6RjkiZqUP6wrgViezGcrjDc7vh8aVgJ3dDZwCNJ J/JUSpyPK5SiDpaByZZ4ozEJMtmk76sZDp9LZ+GWUteIVNsX401MyWU6WI5CDZ+s 3m7xkDqgLH8LiBoyVrbPDJGltQPvlvu/ML+KPQbQ+VUQIY/eczhSJU0gsHPX16A/ lYaAgqvs3Mm30V03Jax/ZApffrACiz7zTXEkhj9ckSAjJ71EYbAr1SDhktmobZnt 6mYMFHR6VuiUSL5Qo6HdxJi3b6tAzzsAJY5HtX9ZjuUuym5LVwIaMDBhIOmwXbfC iviAL/MY2R0BfSZHNA/vfFqs2XyIzl2RpCLLTHtHT/gxcnQ04e5kcXHLNGgblcaD oUyfkuUsGKN+ZasVBG2vu3UEGeN9mJ+WWlyNE9W7vvBlgUS7ufA6feT4CGXC4UL4 OIVb8po73oMq99oaiSuNoTuUWux6qtnv0oah7ga+zqlm7+msIkGTQoea94EJ9CMu 3KMJbLlPJgd8ObRdmc0eZw+GnJU6qNvtP8zg53W5s76bMJNL3u2AsGx114pkTjkh YRGIRJngT0rWzbE4fa3bh3QDFA9b4ddocqNNEwE0+k/5GwgPDqH5lX6X/7wDEVNo haQrlWjB/VqYxqToIHJqvoxDVZcDRpBN9D4Hw/06qmVX/VkVFKmcx4dXMuy5ADye opA0A8JYxy6Vmae0IKvCwm8EGAEKACYCGwIWIQSPF3dxGKM92pukjmKqyzJDYwBS 2QUCYGUNFAUJDDqR/gEpCRCqyzJDYwBS2cBdIAQZAQoABgUCVSOmlgAKCRByI7Vm eOAlKKaUB/95BM6GPtpIoCCIxgrcloxd3ldrxgc+LU4krN5gtYQkNDj/Ytbop7av RrfptOS5UkxbirvdUNGNwKwgwDQG2oA5ku0VUoWyDYT2V+yNwhfzvPU29wyg0wnW g4bnjq5k6Sl+idvXNqOUw21SIxnI1TLL0EMjP6Ov8uw1z/AXZMiP3sHbBLfLpPU+ FaWUwVdYoOPffNGM0WspKWBaDp9C/jF3H//KJAKY7THoUSMzUXo2E99N8NUfF30C Cg1kURg8EFzvXlUmosPmdhGxOKETpGOSJmpQ/rCuBWJ7MZyuMNzu+HxpWAnd0NnA I0kn8lRKnI8rlKIOloHJlnijMQky2aTvBD4On1znhsMFzW3PpQ7Nq2JcjXC4waki +gj60K3EnwTCvJeJ2u4RTea3wm0lHUT9m0r33S3tDlRZmRrwJARL4LyujR5ZkKEu 4FrLfTMleqP79TazSB6ajrG4lmTPP6/J9K3gZCqG31DT7kelDONe0nZPhmKdU1NO +G0wlwx3CufXfmhK8XJsC+b3gGtGTkI4nQ6HtU6hTmFvKuTpsFw8I6CPBBHvUq29 0tjfp2WHD1nSMUmyxe519rViPuvWrtsludZ0TyjLiQ6b5j/zapiaen+IOrnsdJBJ QPKF8755OneenmCIRYYLrW4HS7YYAr9TeN243X4UbzMa9NuH5v/EX8QBAky2/0ng EgHSX/NkHu0q9kQn5YsL/qQKuLE79lMsThXCq5eo50r+j0uoguXkGSRPaFcSFImM XHTBnMK1iWJHPsY8/K5sidRRa1vE+qYqIrtf/cTpMCEcQkDlU/8xdWknTwYDgxIE NAzrVqTcze0coBgdhEC6vnAPM7eylDYBg18Xrj/Mfd2xwjDC5RiH8PjFdLx6Zqui qsa7K8SFqdJj7TXmXyqNLKD40igup9WdG0aTpXc9qrUJ14Nx6DaOpxG75E1loY/l m8WsXD5CuNIqjZaH5aG4AMLCbwQYAQoAJgIbAhYhBI8Xd3EYoz3am6SOYqrLMkNj AFLZBQJcsIjcBQkLT0lGASkJEKrLMkNjAFLZwF0gBBkBCgAGBQJVI6aWAAoJEHIj tWZ44CUoppQH/3kEzoY+2kigIIjGCtyWjF3eV2vGBz4tTiSs3mC1hCQ0OP9i1uin tq9Gt+m05LlSTFuKu91Q0Y3ArCDANAbagDmS7RVShbINhPZX7I3CF/O89Tb3DKDT CdaDhueOrmTpKX6J29c2o5TDbVIjGcjVMsvQQyM/o6/y7DXP8BdkyI/ewdsEt8uk 9T4VpZTBV1ig49980YzRaykpYFoOn0L+MXcf/8okApjtMehRIzNRejYT303w1R8X fQIKDWRRGDwQXO9eVSaiw+Z2EbE4oROkY5ImalD+sK4FYnsxnK4w3O74fGlYCd3Q 2cAjSSfyVEqcjyuUog6WgcmWeKMxCTLZpO9lmg6eKqb7zs4QukYeDf8OBpeJtn3U 4D8WtbgmeI55rHZ5nCgWJoxb3x6fW7uEDq4Uo4oEaIEg5k7ERIU5NI1/cBAZrBQl EiZns7j6nSybuDfunm9VUtulyNk1n7cw+1SRf+y5kiqIwnSSGajrHkJ7RDCN6Apd EO7XFdPLCdWXNvvs4ZyI/rcnSOqlTJ/WFoRvSubj44QPIHXw+Mb/xFKpRccqyDbo eU+a9h57JGFwUAp/XKr07NrDQUZn5QhRvrfQ8D0O17BSyqcpxGjZOliXruzFz7t5 G+CyUrvpm++KHmVrtJAGBItUHJGFwghXFWe8NfRy+g7Xod/EsJmVOXNOLSenjjK+ qVH5KbMGry+Aleu8CRWkeUZyR26kUMqsD0DDL1pZg7hZKlfyct0CR/xW8d576vFh L5EE6zqPggbg+IfJ29NZqw1RyelXGxDT8YpHM2Q+DZV1bYitTqEWCe3RTl2Kr7cq oVXNMeCdg6d7XYUNNqxiTUDBp1VkmSSBcE/LB7scxjwjcc4i5ePxSTj23wbrvH/w wEbHRpsfFn742cwDMrCUwguQSu/7bzSTkU+/5WvyqTou5m1i1323BfbWPaGbuaT7 eUoIAFRjuBrovU8kY/SJ02MywsJvBBgBCgAPAhsCBQJY5iO2BQkHhOQgAUAJEKrL MkNjAFLZwF0gBBkBCgAGBQJVI6aWAAoJEHIjtWZ44CUoppQH/3kEzoY+2kigIIjG CtyWjF3eV2vGBz4tTiSs3mC1hCQ0OP9i1uintq9Gt+m05LlSTFuKu91Q0Y3ArCDA NAbagDmS7RVShbINhPZX7I3CF/O89Tb3DKDTCdaDhueOrmTpKX6J29c2o5TDbVIj GcjVMsvQQyM/o6/y7DXP8BdkyI/ewdsEt8uk9T4VpZTBV1ig49980YzRaykpYFoO n0L+MXcf/8okApjtMehRIzNRejYT303w1R8XfQIKDWRRGDwQXO9eVSaiw+Z2EbE4 oROkY5ImalD+sK4FYnsxnK4w3O74fGlYCd3Q2cAjSSfyVEqcjyuUog6WgcmWeKMx CTLZpO8WIQSPF3dxGKM92pukjmKqyzJDYwBS2R+5Dp4woT/lj4uJl4664XLdybPt fsMFUOtGYhBK66fyPXbPai+XbvXZSSAOe74QPO1coAQrfTnZmhWk2y8aSLYwwHHa StSa0XCgCGTowSCmqUZFx+GzkGvl948cL+fK0KalU80axs7MMTBblxVbjh2D3L7Y ib65wLTyei/HgMT3inbUp/2XgsrO1AUfd5JLKM0oVhnyLmx3BB7IZBEDytQEBXSH g7+xhru3wBpOyXLb+CXNb0PeL+rubdh2YH4zkq4KqkhWEitWetDBMaf9bcSA0h/D Y+AC+cBXCQ0QhWlQz5Xkyj2yHkX25jgRDlry3nrTTmTtbPxraDyLTyRBt0UhtyYi Ey7XdIP3yLvssieUKnwfP+32iumVYbiVGDUvmzYeEM5A3892WIR6cKBQCs6H2LD6 wyiTl1Z41u5AhfaAAhPd7mzb4GM5U3dwx+7iCCWyp07l2DcOjJ/p6Lx6iYAzAERV wzM/4e9jcsQ1tZXUHgti/pnpdFm7l39xkN4VrQB/RNGBqKSYf3/iU3EveDe7vLCQ tBUp0n6Ch/++Vv1oeGlwC8IaRIXpHAqelPEo99RqPFaI5C+0VBqFarGr6zk4o07u j2UBP1AeJOarz9WV1/8nlucFjLTCwm8EGAEKAA8FAlUjppYCGwIFCQPCZwABQAkQ qssyQ2MAUtnAXSAEGQEKAAYFAlUjppYACgkQciO1ZnjgJSimlAf/eQTOhj7aSKAg iMYK3JaMXd5Xa8YHPi1OJKzeYLWEJDQ4/2LW6Ke2r0a36bTkuVJMW4q73VDRjcCs IMA0BtqAOZLtFVKFsg2E9lfsjcIX87z1NvcMoNMJ1oOG546uZOkpfonb1zajlMNt UiMZyNUyy9BDIz+jr/LsNc/wF2TIj97B2wS3y6T1PhWllMFXWKDj33zRjNFrKSlg Wg6fQv4xdx//yiQCmO0x6FEjM1F6NhPfTfDVHxd9AgoNZFEYPBBc715VJqLD5nYR sTihE6RjkiZqUP6wrgViezGcrjDc7vh8aVgJ3dDZwCNJJ/JUSpyPK5SiDpaByZZ4 ozEJMtmk7xYhBI8Xd3EYoz3am6SOYqrLMkNjAFLZJ0UOoJCGTE+1TxtIIPTfhdM1 +2NGwoBk1OVR/3xHfy81E0UC9KjM/jC8fzF1t4nGkBftbD3jIkigwFNcbrmLfJ96 VeYKZtcw9PrggRDM6sMMURg6Iw2kbNtQiIEburwkUNzAxaYiSo2KmuhF7ZIm3k1i OsqPcPXVB/josNLJDSxfzCcRsLxO+CdQa9qbwbEzrjwi9DXZNN9tO7hYUY1suKJ6 mxCeMwPi+u/2Ecwgm7Vm7qDrrJ/a6kMIq9FR2wXJuxSL8FvFN/WpcViSJc6d/+bE Rti6uMZmCMtKMR0DWh658NSjo+e3fBRFnOK2HmY0zmJJMjnnnc/WoLpes+spGtTj y9O0Cm/pWeSJXNMvmDkrTRunyH4l6LSQXCUAXcjsXcYKv2g1TqS/RAac2OKtdaG/ PXPHqrKJ5s/EIKOz4oWkzMl6WRP36TwdoRxBvyMRrF9znOX/fXHCR/yuf4Eilp8J 6P4B8UMmy6WlPsva4QWFhmc+5c8n2SBdUCAV2mkgwqCpDTR5Cs9jYal1UcxmFZBV OIXakAhe6468IOtyFEyNVYF9taIMDL9YFukl6ZoX7UgdwfnKbQQWBRjjFpcigaNF XuwkEDh4MBNicSOdhoItEg89lEbzxQ== =VIUO -----END PGP PUBLIC KEY BLOCK----- """ sequoia-policy-config-0.8.1/src/check.rs000064400000000000000000000024011046102023000162470ustar 00000000000000use std::io::Read; use std::fs::File; use sequoia_openpgp as openpgp; use openpgp::Result; use sequoia_policy_config::{ConfiguredStandardPolicy, DumpDefault}; fn usage() -> ! { let binary = std::env::args().next() .unwrap_or_else(|| String::from("sequoia-policy-config-check")); eprintln!("Usage: {} [--dump] [config.toml]", binary); eprintln!(""); eprintln!("If no configuration is supplied, the default configuration \ is checked."); std::process::exit(1); } fn main() -> Result<()> { let args = std::env::args().collect::>(); if args.len() > 3 { eprintln!("Expected at most two arguments."); usage(); } let dump = args.get(1).map(|a| a == "--dump").unwrap_or(false); if ! dump && args.len() == 3 { usage(); } let filename_offset = if dump { 2 } else { 1 }; let mut p = ConfiguredStandardPolicy::new(); if let Some(filename) = args.get(filename_offset) { let mut file = File::open(filename)?; let mut bytes = Vec::new(); file.read_to_end(&mut bytes)?; p.parse_bytes(bytes)?; } else { p.parse_default_config()?; } if dump { p.dump(&mut std::io::stdout(), DumpDefault::Template)?; } Ok(()) } sequoia-policy-config-0.8.1/src/dump.rs000064400000000000000000000361541046102023000161530ustar 00000000000000//! Creates a TOML template containing the current configuration. use std::{ collections::BTreeMap, io, time::{SystemTime, UNIX_EPOCH}, }; use sequoia_openpgp::{ packet::Tag, policy::{ AsymmetricAlgorithm, HashAlgoSecurity, StandardPolicy, }, types::{ AEADAlgorithm, HashAlgorithm, SymmetricAlgorithm, }, }; use crate::{ AEAD_ALGO_MAP, ASYMM_ALGO_MAP, ConfiguredStandardPolicy, HASH_ALGO_MAP, PACKET_MAP, Result, SYMM_ALGO_MAP, algo_to_key, known_packet_version, versioned_packet, }; /// Controls how [`ConfiguredStandardPolicy::dump`] emits default /// values. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum DumpDefault { /// Default values are not emitted. /// /// The advantage is that changes to the `StandardPolicy`'s /// defaults are picked up by applications using a policy /// configuration emitted by /// [`ConfiguredStandardPolicy::dump`]. /// /// The disadvantage is that the defaults are somewhat opaque, /// i.e. hard to discover and adjust for the user. Or, it may be /// that the intent of writing out the policy configuration is to /// freeze the policy, i.e. prevent updates to the /// `StandardPolicy`'s defaults to become effective. Implicit, /// Defaults are emitted, but commented out. /// /// Represents a middle ground between [`DumpDefault::Implicit`] /// and [`DumpDefault::Explicit`]: it allows the /// `StandardPolicy`'s defaults to evolve, while allowing the user /// to discover and tweak the results if they wish. Template, /// Default values are made explicit. /// /// The advantage is that default values are made explicit, so /// that users can discover and tweak them. Further, the current /// policy is frozen, i.e. it prevents updates to the /// `StandardPolicy`'s defaults from becoming effective. /// /// The downside is that the policy is frozen, so users are at /// risk of using a stale policy configuration. Explicit, } impl DumpDefault { /// Emits the key according to the variant. fn emit(&self, sink: &mut dyn io::Write, cutoff: Option, cutoff_ref: Option, key: &str) -> Result<()> { self.emit_cond(sink, cutoff, cutoff == cutoff_ref, key) } /// Emits the key according to the variant depending on `omit`. fn emit_cond(&self, sink: &mut dyn io::Write, cutoff: Option, omit: bool, key: &str) -> Result<()> { if omit { match self { DumpDefault::Implicit => return Ok(()), DumpDefault::Template => write!(sink, "#")?, DumpDefault::Explicit => (), } } writeln!(sink, "{} = {}", key, format_value(cutoff))?; Ok(()) } } impl ConfiguredStandardPolicy<'_> { /// Writes the configuration to `sink`. /// /// Writes the configuration to the given writer, so that when the /// policy configuration is parsed again, it results in a policy /// that behaves the same way as this one. /// /// The handling of default cutoff times can be tweaked using the /// [`DumpDefault`] parameter: they can be omitted, emitted but /// commented out, or emitted. /// /// Note that if this policy has been read from a file, this does /// not necessarily reproduce that file exactly: as the parser /// ignores any unknown values, they are not represented in the /// parsed policy. Further, any default disposition settings are /// lost, as they only affect the parsing, and are not represented /// in the resulting policy. pub fn dump(&self, sink: &mut dyn io::Write, w: DumpDefault) -> Result<()> { const REF: StandardPolicy = StandardPolicy::new(); writeln!(sink, "[hash_algorithms]")?; for a in HashAlgorithm::variants() { let Ok(key) = algo_to_key(&HASH_ALGO_MAP, a) else { // If there's an unknown algorithm, don't return an // error. It just means that we're using a version of // sequoia-openpgp that has added support for some new // algorithms. writeln!(sink, "# Can't dump policy for {}: hash algorithm \ not yet supported by sequoia-policy-config", a)?; continue; }; let spir = self.policy.hash_cutoff( a, HashAlgoSecurity::SecondPreImageResistance); let spir_ref = REF.hash_cutoff( a, HashAlgoSecurity::SecondPreImageResistance); let cr = self.policy.hash_cutoff( a, HashAlgoSecurity::CollisionResistance); let cr_ref = REF.hash_cutoff( a, HashAlgoSecurity::CollisionResistance); if spir == cr { w.emit(sink, spir, spir_ref, key)?; } else { w.emit(sink, spir, spir_ref, &format!("{}.second_preimage_resistance", key))?; w.emit(sink, cr, cr_ref, &format!("{}.collision_resistance", key))?; } } writeln!(sink)?; writeln!(sink, "[symmetric_algorithms]")?; for a in SymmetricAlgorithm::variants() { let Ok(key) = algo_to_key(&SYMM_ALGO_MAP, a) else { // If there's an unknown algorithm, don't return an // error. It just means that we're using a version of // sequoia-openpgp that has added support for some new // algorithms. writeln!(sink, "# Can't dump policy for {}: symmetric algorithm \ not yet supported by sequoia-policy-config", a)?; continue; }; let cutoff = self.policy.symmetric_algo_cutoff(a); let cutoff_ref = REF.symmetric_algo_cutoff(a); w.emit(sink, cutoff, cutoff_ref, key)?; } writeln!(sink)?; writeln!(sink, "[asymmetric_algorithms]")?; for a in AsymmetricAlgorithm::variants() { let Ok(key) = algo_to_key(&ASYMM_ALGO_MAP, a) else { // If there's an unknown algorithm, don't return an // error. It just means that we're using a version of // sequoia-openpgp that has added support for some new // algorithms. writeln!(sink, "# Can't dump policy for {}: asymmetric algorithm \ not yet supported by sequoia-policy-config", a)?; continue; }; let cutoff = self.policy.asymmetric_algo_cutoff(a); let cutoff_ref = REF.asymmetric_algo_cutoff(a); w.emit(sink, cutoff, cutoff_ref, key)?; } writeln!(sink)?; writeln!(sink, "[aead_algorithms]")?; for a in AEADAlgorithm::variants() { let Ok(key) = algo_to_key(&AEAD_ALGO_MAP, a) else { // If there's an unknown algorithm, don't return an // error. It just means that we're using a version of // sequoia-openpgp that has added support for some new // algorithms. writeln!(sink, "# Can't dump policy for {}: asymmetric algorithm \ not yet supported by sequoia-policy-config", a)?; continue; }; let cutoff = self.policy.aead_algo_cutoff(a); let cutoff_ref = REF.aead_algo_cutoff(a); w.emit(sink, cutoff, cutoff_ref, key)?; } writeln!(sink)?; writeln!(sink, "[packets]")?; for t in Tag::variants() { let Ok(key) = algo_to_key(&PACKET_MAP, t) else { // If there's an unknown algorithm, don't return an // error. It just means that we're using a version of // sequoia-openpgp that has added support for some new // algorithms. writeln!(sink, "# Can't dump policy for {}: packet not yet \ supported by sequoia-policy-config", t)?; continue; }; if versioned_packet(t) { // We need to be clever here. First, compute a // histogram of packet version cutoffs. let mut histo: BTreeMap, Vec> = Default::default(); // Constant cutoff time in the reference? let mut ref_constant = true; let ref_0 = REF.packet_tag_version_cutoff(t, 0); for v in 0..=255 { let cutoff = self.policy.packet_tag_version_cutoff(t, v); histo.entry(cutoff).or_default().push(v); ref_constant &= REF.packet_tag_version_cutoff(t, v) == ref_0; } if histo.len() == 1 { // All versions have the same cutoff. Collapse // into unversioned cutoff. let cutoff = *histo.keys().next().unwrap(); let cutoff_ref = REF.packet_tag_version_cutoff(t, 0); w.emit_cond(sink, cutoff, cutoff == cutoff_ref && ref_constant, key)?; continue; } // Collapse the largest group into the default // disposition. let mut histo = histo.into_iter().collect::>(); histo.sort_by_key(|(_, versions)| versions.len()); let (default_disposition, default_group) = histo.pop().unwrap(); let default_ref = REF.packet_tag_version_cutoff(t, default_group[0]); w.emit_cond(sink, default_disposition, default_disposition == default_ref && ref_constant, &format!("{}.default_disposition", key))?; let mut unknown_versions = Vec::new(); for (cutoff, versions) in histo { for v in versions { let cutoff_ref = REF.packet_tag_version_cutoff(t, v); w.emit_cond( sink, cutoff, cutoff == cutoff_ref && cutoff == default_disposition, &format!("{}.v{}", key, v))?; if ! known_packet_version(t, v) { unknown_versions.push(format!("v{}", v)); } } } if ! unknown_versions.is_empty() { writeln!(sink, "{}.ignore_invalid = {:?}", key, &unknown_versions)?; } } else { let cutoff = self.policy.packet_tag_version_cutoff(t, 0); let cutoff_ref = REF.packet_tag_version_cutoff(t, 0); w.emit(sink, cutoff, cutoff_ref, key)?; } } Ok(()) } } /// Formats the given cutoff value. fn format_value(v: Option) -> String { match v { None => "\"always\"".into(), Some(cutoff) => if cutoff == UNIX_EPOCH { "\"never\"".into() } else { use chrono::{DateTime, NaiveTime, Utc}; let d: DateTime = cutoff.into(); if d.time().signed_duration_since( NaiveTime::from_hms_opt(0, 0, 0).unwrap()).is_zero() { d.format("%Y-%m-%d").to_string() } else { d.format("%Y-%m-%dT%H:%M:%SZ").to_string() } } } } #[cfg(test)] mod tests { use super::*; #[test] fn roundtrip_default() -> Result<()> { test_roundtrip(Default::default()) } quickcheck::quickcheck! { fn roundtrip(p: ConfiguredStandardPolicy<'static>) -> bool { test_roundtrip(p).unwrap(); true } } fn test_roundtrip(p: ConfiguredStandardPolicy) -> Result<()> { for v in [DumpDefault::Explicit, DumpDefault::Template, DumpDefault::Implicit] { let mut sink = Vec::new(); p.dump(&mut sink, v)?; eprintln!("{:?}:", v); eprintln!("{}", std::str::from_utf8(&sink)?); let mut q = ConfiguredStandardPolicy::new(); q.parse_bytes(&sink)?; assert_effectively_eq(&p.policy, &q.policy); } Ok(()) } fn assert_effectively_eq(a: &StandardPolicy, b:&StandardPolicy) { // XXX: The parser ignores unknown algorithms, even though the // standard policy could represent them. Therefore, we only // compare known algorithms. for alg in HashAlgorithm::variants() { assert_eq!( a.hash_cutoff(alg, HashAlgoSecurity::SecondPreImageResistance), b.hash_cutoff(alg, HashAlgoSecurity::SecondPreImageResistance), "differ on second preimage resistance cutoff for {}", alg); assert_eq!( a.hash_cutoff(alg, HashAlgoSecurity::CollisionResistance), b.hash_cutoff(alg, HashAlgoSecurity::CollisionResistance), "differ on collision resistance cutoff for {}", alg); } for alg in SymmetricAlgorithm::variants() { assert_eq!( a.symmetric_algo_cutoff(alg), b.symmetric_algo_cutoff(alg), "differ on symmetric algo cutoff for {}", alg); } for alg in AEADAlgorithm::variants() { assert_eq!( a.aead_algo_cutoff(alg), b.aead_algo_cutoff(alg), "differ on aead algo cutoff for {}", alg); } for alg in AsymmetricAlgorithm::variants() { assert_eq!( a.asymmetric_algo_cutoff(alg), b.asymmetric_algo_cutoff(alg), "differ on asymmetric algo cutoff for {}", alg); } for t in Tag::variants() { for v in 0..=255 { // XXX: The parser flat out ignores unknown packet // versions, even though the standard policy can // represent unknown values. Therefore, we only // compare known versions. if ! known_packet_version(t, v) { continue; } assert_eq!( a.packet_tag_version_cutoff(t, v), b.packet_tag_version_cutoff(t, v), "differ on {} version {} cutoff", t, v); } } } } sequoia-policy-config-0.8.1/src/lib.rs000064400000000000000000002111371046102023000157500ustar 00000000000000//! Configures a `StandardPolicy` using a configuration file. //! //! Sequoia's [`StandardPolicy`] can be configured using Rust. As //! with most things, Sequoia's low-level library avoids imposing a //! policy on users of the library, like where a configuration file //! should be or even what format it should have. When necessary, it //! is up to the application to provide an interface, and to configure //! the policy appropriately. //! //! [`StandardPolicy`]: https://docs.rs/sequoia-openpgp/1.*/sequoia_openpgp/policy/struct.StandardPolicy.html //! //! This library provides a high-level interface that parses a //! configuration file, and returns a configured `StandardPolicy`. //! //! # Format //! //! The file format is based on [TOML]. It contains several sections, //! one for hash algorithms, one for asymmetric algorithms, etc. //! //! [TOML]: https://toml.io/ //! //! ## Forward Compatibility //! //! This parser is strict, but we want the configuration format to be //! forwards compatible so that the same configuration file can be //! used with different versions of the parser. //! //! ### Dealing with New Keys //! //! Unknown sections and unknown keys cause a parse error. To allow //! configuration files a degree of backwards compatibility, it is //! possible to set the per-map `ignore_invalid` key to the key or the //! list of keys that should be ignored if they are not recognized. //! For instance, if Sequoia adds support for `SHA4`, then you could //! do the following to unconditionally reject `SHA4` while ensuring //! that the configuration is still readable by older versions of //! Sequoia that don't know about `SHA4`: //! //! ```toml //! [hash_algorithms] //! ignore_invalid = [ "sha4" ] //! sha4 = never //! ``` //! //! (The same principle applies to sections.) //! //! ### Dealing with Type Changes //! //! Most keys are string types. In the future, we may want to make a //! given algorithm or data structure's configuration more nuanced. A //! logical way to do this is to change the key from taking a string //! type to taking a map type. //! //! To support this type of change, all keys that take a string are //! also recognized as maps with a single key, `default_disposition`. //! Thus, if `key` is ever extended in this way, //! `key.default_disposition` can be used to control the configuration //! of older versions, and new versions can use the configuration //! parameters. //! //! For instance, imagine that AES128 is found to be vulnerable to an //! attack called `foo` in certain, detectable situations. We could //! extend AES128 with a new key (`foo`) that is respected when those //! conditions are detected. This can be expressed in the following, //! backwards compatible manner: //! //! ```toml //! [symmetric_algorithms] //! aes128.default_disposition = "always" //! aes128.foo = "2023-01-01" //! aes128.ignore_invalid = "foo" //! ``` //! //! ## Cutoff Times //! //! Most settings take a so-called cutoff time. The cutoff time is //! the time at which an algorithm (e.g., the broken [SHA-1] hash //! algorithm) or a data structure (e.g. the obsolete [SED packet]) //! should no longer be considered valid. Using a cutoff time //! provides more nuance than simply marking an algorithm as invalid. //! In particular, it allows sun setting algorithms that have been //! weakened, but are not yet completely broken, and using data that //! has been saved to a trusted medium before its security was broken. //! //! Cutoff times are expressed using TOML's `datetime` datatype, which //! is an [RFC 3339] formatted timestamp. The following variants are //! valid: //! //! [SHA-1]: https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-07#section-14.1 //! [SED packet]: https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh-07#section-5.7 //! //! Offset datetime: //! //! ```toml //! [hash_algorithms] //! sha1 = 2010-01-01T00:00:00Z //! ``` //! //! Local datetime: //! //! ```toml //! [hash_algorithms] //! sha1 = 2010-01-01T00:00:00+00:00 //! ``` //! //! Local date (interpreted as midnight in UTC): //! //! ```toml //! [hash_algorithms] //! sha1 = 2010-01-01 //! ``` //! //! The local time format is not supported as it doesn't make sense in //! this context. //! //! [RFC 3339]: https://www.rfc-editor.org/rfc/rfc3339 //! //! Two special values are also supported: `always` means that the //! algorithm or data structure should always be considered valid, and //! `never` means that the algorithm or data structure should never be //! considered valid. These values are checked for in a //! case-sensitive manner. //! //! ```toml //! [hash_algorithms] //! sha1 = "never" //! ``` //! //! ## Default Disposition //! //! In some situations, it is desirable to only allow a fixed set of //! algorithms. Using the cutoff mechanism, it is possible to accept //! or reject each of the known algorithms, but unknown algorithms, //! i.e., those that Sequoia will add in the future, and will likely //! enable by default, can't be rejected in this way, because their //! name is---by definition---not yet known. //! //! To accommodate this usage, it is possible to set an algorithm //! class or data structure class's default disposition using the //! `default_disposition` key. Currently, only one value is supported //! for this key: `never`. If this key is present in a section, then //! that key is processed first, and all algorithms are set to be //! rejected. The rest of the keys are then processed as usual. //! //! The following example shows how to only allow the SHA256 and //! SHA512 hash functions. Even if a theoretical SHA4 hash function //! is added to Sequoia, it will be rejected by this configuration. //! //! ```toml //! [hash_algorithms] //! sha256.collision_resistance = "always" //! sha256.second_preimage_resistance = "always" //! sha512.collision_resistance = "always" //! sha512.second_preimage_resistance = "always" //! default_disposition = "never" //! ``` //! //! ## Sections //! //! ### Hash Functions //! //! Hash algorithms are used to ensure multiple properties. Of //! particular relevance in the context of OpenPGP are collision //! resistance, and second preimage resistance. In some contexts like //! self signatures, only second preimage resistance is required. In //! other contexts, both properties are required. As collision //! resistance is much easier to attack, these two properties can be //! set separately. //! //! You configure just the second preimage resistance cutoff by //! setting the `ALGO.second_preimage_resistance` key. You configure //! just the collision resistance cutoff by setting the //! `ALGO.collision_resistance` key. Setting the `ALGO` key is //! shorthand for setting both. //! //! A hash algorithm's key is the lower-case version of the value //! returned by the [`Display` name][hash-display]. For instance, //! SHA1 is `sha1`. //! //! [hash-display]: https://docs.rs/sequoia-openpgp/1.10.0/sequoia_openpgp/types/enum.HashAlgorithm.html#impl-Display //! //! ```toml //! [hash_algorithms] //! md5 = "never" //! sha1.second_preimage_resistance = 2030-01-01 //! sha1.collision_resistance = 2022-01-01 //! sha512 = "always" //! ``` //! //! ### Symmetric Algorithms //! //! Like hash algorithms, [symmetric algorithms] can be rejected //! outright or have a cutoff date. They don't have any subkeys like //! `collision_resistance`, so there is only one way to set the //! cutoff: using the `algo` key. //! //! [symmetric algorithms]: https://docs.rs/sequoia-openpgp/1.10.0/sequoia_openpgp/types/enum.SymmetricAlgorithm.html#impl-Display //! //! The unencrypted variant, the unknown variants, and the private //! variants cannot currently be set. //! //! ```toml //! [symmetric_algorithms] //! cast5 = "never" //! aes128 = "always" //! ``` //! //! ### Asymmetric Algorithms //! //! Like symmetric algorithms, [asymmetric algorithms] can be rejected //! outright or have a cutoff date. //! //! [asymmetric algorithms]: https://docs.sequoia-pgp.org/sequoia_openpgp/policy/enum.AsymmetricAlgorithm.html#impl-Display //! //! The unknown variants, and the private variants cannot currently be //! set. //! //! ```toml //! [asymmetric_algorithms] //! rsa1024 = "never" //! rsa2048 = 2028-01-01 //! ``` //! //! ### AEAD Algorithms //! //! Like symmetric algorithms, [AEAD algorithms] can be rejected //! outright or have a cutoff date. //! //! [AEAD algorithms]: https://docs.rs/sequoia-openpgp/1.10.0/sequoia_openpgp/types/enum.AEADAlgorithm.html#impl-Display //! //! The unknown variants, and the private variants cannot currently be //! set. //! //! ```toml //! [aead_algorithms] //! eax = "never" //! ocb = "always" //! ``` //! //! ### Packets //! //! Packets can be rejected outright or have a cutoff date. The [SED //! packet] is, for instance, considered broken, and messages that use //! it should generally be rejected unless they are known to not be //! from an attacker, e.g., because they were stored on a trusted //! medium before the attack was feasible. //! //! It is also possible to reject particular versions of a packet. In //! this case, the packet is a map and the fields `vX` where `X` is a //! `u8` can be used to set the cutoff for version `X` of the packet. //! This mechanism is only supported for packets that actually are //! versioned, and only for known versions. (Unknown versions can //! still be set in a forwards compatible way using the //! `ignore_invalid` key.) //! //! The packets are named after the [names of the Packet variants]. //! //! [names of the Packet variants]: https://docs.rs/sequoia-openpgp/1.10.0/sequoia_openpgp/packet/enum.Tag.html#variants //! //! The reserved packet, the unknown variants, and the private //! variants cannot currently be set. //! //! ```toml //! [packets] //! sed = "never" //! seip = 2028-01-01 //! //! signature.v3 = 2017-01-01 //! signature.v4 = 2030-01-01 //! signature.v6 = "always" //! # v6 signatures are coming, but not yet recognized. //! signature.ignore_invalid = "v6" //! ``` //! //! ## Examples //! //! The following example shows how to use a configuration file to //! configure a `StandardPolicy`: //! //! ```rust //! use sequoia_openpgp as openpgp; //! use openpgp::policy::HashAlgoSecurity; //! use openpgp::types::HashAlgorithm; //! //! use sequoia_policy_config::ConfiguredStandardPolicy; //! //! # fn main() -> openpgp::Result<()> { //! let mut p = ConfiguredStandardPolicy::new(); //! p.parse_bytes(b"[hash_algorithms] //! sha1.collision_resistance = \"never\"")?; //! let p = &p.build(); //! //! assert_eq!(p.hash_cutoff(HashAlgorithm::SHA1, //! HashAlgoSecurity::CollisionResistance), //! Some(std::time::UNIX_EPOCH)); //! # Ok(()) } //! ``` #![allow(clippy::type_complexity)] use std::collections::HashSet; use std::env; use std::io; use std::path::Path; use std::path::PathBuf; use std::string::String; use std::time::SystemTime; use std::time::UNIX_EPOCH; use sequoia_openpgp as openpgp; use openpgp::packet::Tag; use openpgp::policy::AsymmetricAlgorithm; use openpgp::policy::StandardPolicy; use openpgp::policy::HashAlgoSecurity; use openpgp::types::AEADAlgorithm; use openpgp::types::HashAlgorithm; use openpgp::types::SymmetricAlgorithm; use anyhow::Context as _; use chrono::DateTime; use chrono::NaiveDate; use chrono::TimeZone; use chrono::Utc; use toml::value; use toml::Value; mod dump; pub use dump::DumpDefault; #[cfg(test)] mod testdata; #[derive(Clone, Debug)] pub struct ConfiguredStandardPolicy<'a> { policy: StandardPolicy<'a>, } type Result = std::result::Result; /// Errors used in this crate. /// /// Note: This enum cannot be exhaustively matched to allow future /// extensions. #[non_exhaustive] #[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)] pub enum Error { /// Parse error #[error("Parse error: {0}")] ParseError(String), /// A Relative Path was provided where an absolute path was expected. #[error("Relative path not allowed: {0}")] RelativePathError(PathBuf), /// An algorithm is not known to this crate. #[error("Unknown algorithm: {0}")] UnknownAlgorithm(String), } /// A timestamp. /// /// None is always. type Timestamp = Option; /// Always accept. const ALWAYS: Timestamp = None; /// Never accept. /// /// By setting the acceptance time to the unix epoch, we never accept /// anything. const NEVER: Timestamp = Some(UNIX_EPOCH); // Parses a timestamp stored in a toml value. // // Recognizes the special values "always" and "never". fn parse_time(t: &Value) -> Result { let t = match t { Value::String(t) => t.clone(), Value::Datetime(t) => t.to_string(), _ => Err(Error::ParseError( format!("timestamp is not a string ({:?})", t)))?, }; Ok(match &t[..] { "always" => ALWAYS, "never" => NEVER, t => { let t = if let Ok(p) = DateTime::parse_from_rfc3339(t) { p.into() } else { let t = NaiveDate::parse_from_str(t, "%Y-%m-%d") .context(format!("Parsing timestamp {}", t))? .and_hms_opt(0, 0, 0).expect("valid time"); let t: DateTime = Utc.from_utc_datetime(&t); t.into() }; Some(t) } }) } // Returns an error if a key is unknown. // // known_keys better be lowercase. fn check_sections(path: Option<&str>, section: &value::Map, known_keys: &[&str]) -> Result<()> { // known_keys better be lowercase. known_keys.iter().for_each( |&s| debug_assert_eq!(&s.to_lowercase()[..], s)); let prefix = || if let Some(path) = path { format!("{}.", path) } else { "".to_string() }; let keys: HashSet<&str> = section .keys() .map(|s| s.as_str()) .collect(); // The set of allowed keys are the known keys, plus // "ignore_invalid", and the value of "ignore_invalid". let mut allowed_keys: Vec<&str> = known_keys.to_vec(); if let Some(ignore) = section.get("ignore_invalid") { allowed_keys.push("ignore_invalid"); match ignore { Value::String(k) => allowed_keys.push(k.as_str()), Value::Array(ks) => { for k in ks { if let Value::String(k) = k { allowed_keys.push(k.as_str()); } else { Err(Error::ParseError(format!( "'{}ignore_invalid' takes a string \ or an array of strings", prefix())))? } } } _ => { return Err(Error::ParseError(format!( "Invalid value for '{}ignore_invalid': {}, \ expected a string or an array of strings", prefix(), ignore)).into()); } } } // Now check if there are any unknown sections. let unknown_keys = keys .difference(&allowed_keys.into_iter().collect()) .map(|s| *s) .collect::>(); if ! unknown_keys.is_empty() { return Err(Error::ParseError(format!( "{} has unknown keys: {}, valid keys are: {}", if let Some(path) = path { path } else { "top-level section" }, unknown_keys.join(", "), // We don't include the keys listed in ignore_invalid. known_keys.join(", "))).into()); } Ok(()) } const HASH_ALGO_PROPS: &[(&str, HashAlgoSecurity)] = &[ ("second_preimage_resistance", HashAlgoSecurity::SecondPreImageResistance), ("collision_resistance", HashAlgoSecurity::CollisionResistance), ]; const HASH_ALGO_MAP: [(&str, HashAlgorithm, &[(&str, HashAlgoSecurity)]); 9] = [ ("md5", HashAlgorithm::MD5, HASH_ALGO_PROPS), ("sha1", HashAlgorithm::SHA1, HASH_ALGO_PROPS), ("ripemd160", HashAlgorithm::RipeMD, HASH_ALGO_PROPS), ("sha256", HashAlgorithm::SHA256, HASH_ALGO_PROPS), ("sha384", HashAlgorithm::SHA384, HASH_ALGO_PROPS), ("sha512", HashAlgorithm::SHA512, HASH_ALGO_PROPS), ("sha224", HashAlgorithm::SHA224, HASH_ALGO_PROPS), ("sha3-256", HashAlgorithm::SHA3_256, HASH_ALGO_PROPS), ("sha3-512", HashAlgorithm::SHA3_512, HASH_ALGO_PROPS), ]; const ASYMM_ALGO_MAP: [(&str, AsymmetricAlgorithm, &[(&str, ())]); 24] = [ ("rsa1024", AsymmetricAlgorithm::RSA1024, &[]), ("rsa2048", AsymmetricAlgorithm::RSA2048, &[]), ("rsa3072", AsymmetricAlgorithm::RSA3072, &[]), ("rsa4096", AsymmetricAlgorithm::RSA4096, &[]), ("elgamal1024", AsymmetricAlgorithm::ElGamal1024, &[]), ("elgamal2048", AsymmetricAlgorithm::ElGamal2048, &[]), ("elgamal3072", AsymmetricAlgorithm::ElGamal3072, &[]), ("elgamal4096", AsymmetricAlgorithm::ElGamal4096, &[]), ("dsa1024", AsymmetricAlgorithm::DSA1024, &[]), ("dsa2048", AsymmetricAlgorithm::DSA2048, &[]), ("dsa3072", AsymmetricAlgorithm::DSA3072, &[]), ("dsa4096", AsymmetricAlgorithm::DSA4096, &[]), ("nistp256", AsymmetricAlgorithm::NistP256, &[]), ("nistp384", AsymmetricAlgorithm::NistP384, &[]), ("nistp521", AsymmetricAlgorithm::NistP521, &[]), ("brainpoolp256", AsymmetricAlgorithm::BrainpoolP256, &[]), ("brainpoolp384", AsymmetricAlgorithm::BrainpoolP384, &[]), ("brainpoolp512", AsymmetricAlgorithm::BrainpoolP512, &[]), ("cv25519", AsymmetricAlgorithm::Cv25519, &[]), ("x25519", AsymmetricAlgorithm::X25519, &[]), ("ed25519", AsymmetricAlgorithm::Ed25519, &[]), ("x448", AsymmetricAlgorithm::X448, &[]), ("ed448", AsymmetricAlgorithm::Ed448, &[]), ("eddsa", AsymmetricAlgorithm::EdDSA, &[]), ]; #[allow(deprecated)] const SYMM_ALGO_MAP: [(&str, SymmetricAlgorithm, &[(&str, ())]); 11] = [ ("idea", SymmetricAlgorithm::IDEA, &[]), ("tripledes", SymmetricAlgorithm::TripleDES, &[]), ("cast5", SymmetricAlgorithm::CAST5, &[]), ("blowfish", SymmetricAlgorithm::Blowfish, &[]), ("aes128", SymmetricAlgorithm::AES128, &[]), ("aes192", SymmetricAlgorithm::AES192, &[]), ("aes256", SymmetricAlgorithm::AES256, &[]), ("twofish", SymmetricAlgorithm::Twofish, &[]), ("camellia128", SymmetricAlgorithm::Camellia128, &[]), ("camellia192", SymmetricAlgorithm::Camellia192, &[]), ("camellia256", SymmetricAlgorithm::Camellia256, &[]), ]; const AEAD_ALGO_MAP: [(&str, AEADAlgorithm, &[(&str, ())]); 3] = [ ("eax", AEADAlgorithm::EAX, &[]), ("ocb", AEADAlgorithm::OCB, &[]), ("gcm", AEADAlgorithm::GCM, &[]), ]; const PACKET_MAP: [(&str, Tag, &[(&str, u8)]); 19] = [ ("pkesk", Tag::PKESK, &[("v3", 3), ("v5", 5), ("v6", 6)]), ("signature", Tag::Signature, &[("v3", 3), ("v4", 4), ("v5", 5), ("v6", 6)]), ("skesk", Tag::SKESK, &[("v4", 4), ("v5", 5), ("v6", 6)]), ("onepasssig", Tag::OnePassSig, &[("v3", 3), ("v6", 6)]), ("secretkey", Tag::SecretKey, &[("v4", 4), ("v5", 5), ("v6", 6)]), ("publickey", Tag::PublicKey, &[("v4", 4), ("v5", 5), ("v6", 6)]), ("secretsubkey", Tag::SecretSubkey, &[("v4", 4), ("v5", 5), ("v6", 6)]), ("compresseddata", Tag::CompressedData, &[]), ("sed", Tag::SED, &[]), ("marker", Tag::Marker, &[]), ("literal", Tag::Literal, &[]), ("trust", Tag::Trust, &[]), ("userid", Tag::UserID, &[]), ("publicsubkey", Tag::PublicSubkey, &[("v4", 4), ("v5", 5), ("v6", 6)]), ("userattribute", Tag::UserAttribute, &[]), ("seip", Tag::SEIP, &[("v1", 1), ("v2", 2)]), ("mdc", Tag::MDC, &[]), ("aed", Tag::AED, &[("v1", 1)]), ("padding", Tag::Padding, &[]), ]; /// Given a map and an algorithm (or packet tag), returns the key /// usable in the configuration file. fn algo_to_key(map: &[(&'static str, A, &[V])], a: A) -> std::result::Result<&'static str, Error> where A: Copy + PartialEq + ToString, { map.iter().find_map(|e| (e.1 == a).then_some(e.0)) .ok_or_else(|| Error::UnknownAlgorithm(a.to_string())) } /// Given a packet tag, returns whether `v` is a known version. fn known_packet_version(t: Tag, v: u8) -> bool { PACKET_MAP.iter().find(|e| e.1 == t) .map(|(_, _, versions)| versions.iter().any(|(_, known)| *known == v)) .unwrap_or(false) } /// Returns whether the given packet type is versioned. fn versioned_packet(t: Tag) -> bool { matches!(t, | Tag::PKESK | Tag::Signature | Tag::SKESK | Tag::OnePassSig | Tag::SecretKey | Tag::PublicKey | Tag::SecretSubkey | Tag::PublicSubkey | Tag::SEIP | Tag::AED) } impl Default for ConfiguredStandardPolicy<'_> { fn default() -> Self { Self::new() } } impl<'a> ConfiguredStandardPolicy<'a> { /// The default environment variable. pub const ENV_VAR: &'static str = "SEQUOIA_CRYPTO_POLICY"; /// The default configuration file. pub const CONFIG_FILE: &'static str = "/etc/crypto-policies/back-ends/sequoia.config"; /// Returns a new `ConfiguredStandardPolicy` with a default /// `StandardPolicy`. /// /// Normally you'll want to follow this up with a call to /// [`ConfiguredStandardPolicy::parse_bytes`] or /// [`ConfiguredStandardPolicy::parse_default_config`]. pub fn new() -> Self { Self::from_policy(StandardPolicy::new()) } /// Returns a new `ConfiguredStandardPolicy`. /// /// The `StandardPolicy` is created using [`StandardPolicy::at`]. /// /// [`StandardPolicy::at`]: https://docs.rs/sequoia-openpgp/1.10.0/sequoia_openpgp/policy/struct.StandardPolicy.html#method.at /// /// Normally you'll want to follow this up with a call to /// [`ConfiguredStandardPolicy::parse_bytes`] or /// [`ConfiguredStandardPolicy::parse_default_config`]. pub fn at(t: T) -> Self where T: Into { Self::from_policy(StandardPolicy::at(t)) } /// Returns a new `ConfiguredStandardPolicy` using the provided /// `StandardPolicy`. /// /// Normally you'll want to follow this up with a call to /// [`ConfiguredStandardPolicy::parse_bytes`] or /// [`ConfiguredStandardPolicy::parse_default_config`]. pub fn from_policy(policy: StandardPolicy<'a>) -> Self { ConfiguredStandardPolicy { policy } } /// Parses the configuration file specified by the environment /// variable. /// /// To use the default environment variable, specify /// [`ConfiguredStandardPolicy::ENV_VAR`]. /// /// This function returns: `Ok(true)` if the policy was /// configured; `Ok(false)` if the policy was not configured; or, /// an error if there was a problem opening, reading, or parsing /// the configuration file. /// /// Specifically: /// /// - If the specified environment variable is not set, this /// function returns `Ok(false)` to indicate that the policy /// was not configured. /// /// - If the specified environment variable is set to the empty /// string, no configuration file is read, but the policy is /// considered to be configured (that is, the empty string /// means to use the policy as is), and the function returns /// `Ok(true)`. /// /// - If the environment variable is set to a relative path, /// this function returns an error. /// /// - If the environment variable is set to an absolute path, /// the specified file is parsed. If an error occurs while /// opening (including that the file does not exist), reading, /// or parsing the configuration file, the error is returned. /// If the configuration file is successfully parsed, the /// function returns `Ok(true)` to indicate that the policy is /// configured. pub fn parse_env_config(&mut self, env_var: &str) -> Result { let config_file = match env::var(env_var) { // Environment variable wasn't set. Err(_err) => return Ok(false), Ok(filename) => filename, }; if config_file.is_empty() { // We're configured: the empty string means to just use // the policy as is. return Ok(true); } let config_file = PathBuf::from(config_file); if config_file.is_relative() { // A relative path is an error. let err = anyhow::Error::from( Error::RelativePathError(config_file)); return Err(err) .context(format!("Invalid value for {}", env_var)); } // We've got a configuration file. Parse it. let config = match std::fs::read(&config_file) { Err(err) => { let err = anyhow::Error::from(err); return Err(err).with_context(|| { format!("Reading {:?}", config_file) }); } Ok(config) => config, }; self.parse_bytes(config) .with_context(|| { format!("Parsing {:?}", config_file) })?; // We're configured. Ok(true) } /// Configures the policy using the specified configuration file. /// /// If `config_file` does not exist, returns `Ok(false)` to /// indicate that the policy was not configured. /// /// If an error occurs while opening, reading, or parsing the /// configuration file, the error is returned. /// /// Otherwise, `Ok(true)` is returned to indicate that the /// policy was configured. pub fn parse_config_file

(&mut self, config_file: P) -> Result where P: AsRef { let config_file = config_file.as_ref(); let config = match std::fs::read(config_file) { Err(err) => { if err.kind() == io::ErrorKind::NotFound { // A missing configuration file is not an error. return Ok(false); } else { let err = anyhow::Error::from(err); return Err(err).with_context(|| { format!("Reading {:?}", config_file) }); } } Ok(config) => config, }; self.parse_bytes(config) .with_context(|| { format!("Parsing {:?}", config_file) })?; // We're configured. Ok(true) } /// Parses the specified configuration. /// /// This function first tries to configure the policy using the /// configuration file specified in the environment variable /// `env_var` using /// [`ConfiguredStandardPolicy::parse_env_config`]. If that /// returns `Ok(false)`, then it tries to parse `config_file` /// using [`ConfiguredStandardPolicy::parse_config_file`]. pub fn parse_config

(&mut self, env_var: &str, config_file: P) -> Result where P: AsRef { let config_file = config_file.as_ref(); match self.parse_env_config(env_var) { Ok(false) => { // No error and we didn't configure the policy. Fallback // to the configuration file. self.parse_config_file(config_file) } otherwise => otherwise, } } /// Parses the default configuration. /// /// This first tries to parse the configuration file specified in /// the environment variable `SEQUOIA_CRYPTO_POLICY`. See /// [`ConfiguredStandardPolicy::parse_env_config`] for the /// semantics. /// /// If `ConfiguredStandardPolicy::parse_env_config` doesn't /// configure the policy (i.e., it returns `Ok(false)`), this /// function tries to parse /// [`ConfiguredStandardPolicy::CONFIG_FILE`] using /// [`ConfiguredStandardPolicy::parse_config_file`]. pub fn parse_default_config(&mut self) -> Result { self.parse_config(Self::ENV_VAR, Self::CONFIG_FILE) } /// Configures the policy according to the configuration data. pub fn parse_bytes(&mut self, config: B) -> Result<()> where B: AsRef<[u8]> { let config = config.as_ref(); let config = std::str::from_utf8(config)?.parse::()?; let config = if let Value::Table(config) = config { config } else { return Err(Error::ParseError( "Expected toml sections".into()).into()); }; check_sections( None, &config, &[ "hash_algorithms", "asymmetric_algorithms", "symmetric_algorithms", "aead_algorithms", "packets", ])?; macro_rules! doit { (// The name of the section (&str). $section_name:literal, // HASH_ALGO_MAP, etc. $algo_map:ident, // A callback that consumes the values: // // fn set(default: Option, // properties: Vec<(AlgorithmId, Timestamp)>) $set:expr, // An iterator over all of the variants. If the // default_disposition key is set, $set is called once // for each variant. $variants:expr) => { if let Some(section) = config.get($section_name) { let section = if let Value::Table(section) = section { section } else { return Err(Error::ParseError( format!("{} is not a map", $section_name)).into()); }; let mut keys = $algo_map.into_iter() .map(|(k, _, _)| k) .collect::>(); keys.push("default_disposition"); check_sections( Some($section_name), §ion, &keys[..])?; // Handle default_disposition first. It is the // default; other settings override it. if let Some(disposition) = section.iter().find_map(|(k, d)| { if k == "default_disposition" { Some(d) } else { None } }) { match disposition.as_str() { // Reject everything by default. Some("never") => { // We assume that all types are a u8. // This is currently the case. for algo in $variants { $set(algo.into(), (Some(NEVER), vec![])); } } _ => { return Err(Error::ParseError(format!( "{}.default_disposition: \ invalid value ({:?}), expected never", $section_name, disposition)).into()); } } } // Iterate over the keys/value pairs. for (k, v) in section { // We already handled "default_disposition" above. if k == "default_disposition" { continue; } // Is the key known? let metadata = $algo_map .into_iter() .find_map(|(key, algo, props)| { if k == key { Some((algo, props)) } else { None } }); let (algo, props) = if let Some((algo, props)) = metadata { (algo, props) } else { // It's unknown, but in "ignore_invalid" // (otherwise check_sections would have // returned an error) so silently skip it. continue; }; // Parse the value. let t: (Option, Vec<(_, Timestamp)>) = match v { Value::Datetime(_) => { let t = Some(parse_time(v)?); (t, vec![]) } Value::String(_) => { let t = Some(parse_time(v)?); (t, vec![]) } Value::Table(m) => { // We got a table. If this key has // properties, then process them. // Otherwise, only look for the // default property. let mut names = props .into_iter() .map(|(name, _id)| name) .cloned() .collect::>(); let ids = props .into_iter() .map(|(_name, id)| id) .cloned() .collect::>(); names.push(&"default_disposition"); check_sections( Some(&format!("{}.{}", $section_name, k)), &m, &names[..])?; let default_disposition = m.get("default_disposition") .map(parse_time).transpose()?; let props: Vec<(_, Timestamp)> = names .into_iter() .zip(ids.into_iter()) .filter_map(|(name, id)| { match m.get(name).map(parse_time) { Some(Ok(t)) => Some(Ok((id, t))), // Parse error. Some(Err(err)) => Some(Err(err)), // property not present. None => None, } }) .collect::>>()?; (default_disposition, props) } v => { return Err(Error::ParseError(format!( "{}.{}: invalid value ({:?}), expected \ a valid timestamp, always, or never", $section_name, k, v)).into()); } }; $set(algo, t); } } } } doit!("hash_algorithms", HASH_ALGO_MAP, |algo: HashAlgorithm, props: (Option, Vec<(HashAlgoSecurity, Timestamp)>)| { let (default_disposition, props) = props; if let Some(default_disposition) = default_disposition { self.policy.reject_hash_property_at( algo, HashAlgoSecurity::SecondPreImageResistance, default_disposition); self.policy.reject_hash_property_at( algo, HashAlgoSecurity::CollisionResistance, default_disposition); } for (id, value) in props { self.policy.reject_hash_property_at( algo, id, value); } }, HashAlgorithm::variants()); doit!("asymmetric_algorithms", ASYMM_ALGO_MAP, |algo: AsymmetricAlgorithm, props: (Option, Vec<((), Timestamp)>)| { // No algorithm has any properties beyond the // default property. assert!(props.1.is_empty()); if let Some(t) = props.0 { self.policy.reject_asymmetric_algo_at( algo, t); } }, AsymmetricAlgorithm::variants()); doit!("symmetric_algorithms", SYMM_ALGO_MAP, |algo: SymmetricAlgorithm, props: (Option, Vec<((), Timestamp)>)| { // No algorithm has any properties beyond the // default property. assert!(props.1.is_empty()); if let Some(t) = props.0 { self.policy.reject_symmetric_algo_at( algo, t); } }, SymmetricAlgorithm::variants()); doit!("aead_algorithms", AEAD_ALGO_MAP, |algo: AEADAlgorithm, props: (Option, Vec<((), Timestamp)>)| { // No algorithm has any properties beyond the // default property. assert!(props.1.is_empty()); if let Some(t) = props.0 { self.policy.reject_aead_algo_at( algo, t); } }, AEADAlgorithm::variants()); doit!("packets", PACKET_MAP, |algo: Tag, props: (Option, Vec<(u8, Timestamp)>)| { if let Some(default_disposition) = props.0 { self.policy.reject_packet_tag_at( algo, default_disposition); } for (version, t) in props.1 { self.policy.reject_packet_tag_version_at( algo, version, t); } }, Tag::variants()); Ok(()) } /// Returns the configured policy. pub fn build(self) -> StandardPolicy<'a> { self.policy } } #[cfg(test)] mod tests { use super::*; use std::time::Duration; use openpgp::Cert; use openpgp::parse::Parse; use quickcheck::{Arbitrary, Gen}; fn arbitrary_cutoff(g: &mut Gen) -> Option { match g.choose(&[0, 1, 2]).unwrap() { 0 => None, 1 => Some(UNIX_EPOCH), 2 => Some(SystemTime::arbitrary(g)), _ => unreachable!(), } } impl Arbitrary for ConfiguredStandardPolicy<'static> { fn arbitrary(g: &mut Gen) -> Self { let mut p = ConfiguredStandardPolicy::default(); for _ in 0..u8::arbitrary(g) { let cutoff = arbitrary_cutoff(g); match g.choose(&[0, 1, 2, 3, 4]).unwrap() { // Hash algorithms. 0 => { let variants = HashAlgorithm::variants().collect::>(); let a = g.choose(&variants).unwrap(); if let Some(sec) = g.choose(&[ Some(HashAlgoSecurity::SecondPreImageResistance), Some(HashAlgoSecurity::CollisionResistance), None, ]).unwrap() { p.policy.reject_hash_property_at(*a, *sec, cutoff); } else { p.policy.reject_hash_at(*a, cutoff); } }, // Symmetric algorithms. 1 => { let variants = SymmetricAlgorithm::variants().collect::>(); let a = g.choose(&variants).unwrap(); p.policy.reject_symmetric_algo_at(*a, cutoff); }, // Asymmetric algorithms. 2 => { let variants = AsymmetricAlgorithm::variants().collect::>(); let a = g.choose(&variants).unwrap(); p.policy.reject_asymmetric_algo_at(*a, cutoff); }, // AEAD algorithms. 3 => { let variants = AEADAlgorithm::variants().collect::>(); let a = g.choose(&variants).unwrap(); p.policy.reject_aead_algo_at(*a, cutoff); }, // Packets. 4 => { let variants = Tag::variants().collect::>(); let t = g.choose(&variants).unwrap(); if versioned_packet(*t) && bool::arbitrary(g) { let versions = PACKET_MAP.iter().find(|e| e.1 == *t).unwrap() .2.iter().map(|(_, v)| *v) .collect::>(); let v = g.choose(&versions).unwrap(); p.policy.reject_packet_tag_version_at( *t, *v, cutoff); } else { p.policy.reject_packet_tag_at(*t, cutoff); } }, _ => unreachable!(), } } p } } // Check that invalid sections cause an error, unless they are // explicitly ignored. #[test] fn invalid_section() -> Result<()> { let mut p = ConfiguredStandardPolicy::new(); assert!(p.parse_bytes(b"x=1").is_err()); // A known section. p.parse_bytes(b"[hash_algorithms] sha1 = \"always\" ").expect("valid"); // A known section and an unknown section. assert!(p.parse_bytes(b"[hash_algorithms] sha1 = \"always\" [x] blah = 1 ").is_err()); // A known section, and an unknown section that we should // ignore. p.parse_bytes(b"ignore_invalid = \"x\" [hash_algorithms] sha1 = \"always\" [x] blah = 1 ").expect("valid"); p.parse_bytes(b"ignore_invalid = [ \"x\", \"y\" ] [hash_algorithms] sha1 = \"always\" [x] blah = 1 [y] blah = 1 ").expect("valid"); // Section names are case sensitive. assert!(p.parse_bytes(b"[HASH_ALGORITHMS] sha1 = \"never\" ").is_err()); assert!(p.parse_bytes(b"[Hash_Algorithms] sha1 = \"never\" ").is_err()); // Underscores can't be replaced by spaces. assert!(p.parse_bytes(b"[HASH_ALGORITHMS] sha1 = \"never\" ").is_err()); Ok(()) } // Make sure invalid keys cause an error, unless they are ignored. #[test] fn invalid_keys() -> Result<()> { let mut p = ConfiguredStandardPolicy::new(); // A known section with known keys. p.parse_bytes(b"[hash_algorithms] sha1 = \"always\" sha224 = \"never\" ").expect("valid"); // A known section with unknown keys. assert!(p.parse_bytes(b"[hash_algorithms] sha1 = \"always\" sha99 = \"never\" ").is_err()); // A known section with unknown keys, the ignore_invalid // directive is in the wrong place. assert!(p.parse_bytes(b" ignore_invalid = \"SHA99\" [hash_algorithms] sha1 = \"always\" SHA99 = \"never\" ").is_err()); // A known section with unknown, but ignored keys. p.parse_bytes(b"[hash_algorithms] ignore_invalid = \"SHA99\" sha1 = \"always\" SHA99 = \"never\" ").expect("valid"); // A known section with unknown keys, which are incorrectly // ignore (wrong case). assert!(p.parse_bytes(b" [hash_algorithms] ignore_invalid = \"SHA99\" sha1 = \"always\" sha99 = \"never\" ").is_err()); Ok(()) } /// Set one property at a time via a config file. Check that is /// has been set. Where appropriate, check that related /// properties have not been changed relative to the standard /// policy. #[test] fn get_set_one() -> Result<()> { let sp = StandardPolicy::new(); let times: [(&str, Timestamp); 5] = [ ("never", NEVER), ("always", ALWAYS), // $ date -u +%s --date='20200101' // 1577836800 ("2020-01-01T00:00:00Z", Some(UNIX_EPOCH + Duration::new(1577836800, 0))), // $ date -u +%s --date='20500101' // 2524608000 ("2050-01-01T00:00:00+00:00", Some(UNIX_EPOCH + Duration::new(2524608000, 0))), // $ date -u +%s --date='21050101' // 4260211200 ("2105-01-01", Some(UNIX_EPOCH + Duration::new(4260211200, 0))), ]; macro_rules! check_hash { ($id:expr, $algo:expr, $props:expr, $time:expr, $config:expr) => { let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes($config).expect("valid"); let p = p.build(); let all = [ HashAlgoSecurity::CollisionResistance, HashAlgoSecurity::SecondPreImageResistance, ]; for prop in all.iter().cloned() { if $props.contains(&prop) { assert_eq!(p.hash_cutoff(*$algo, prop), $time.1, "algo: {}, t: {}", $id, $time.0); } else { // Check that the other security properties // didn't change. assert_eq!( sp.hash_cutoff(*$algo, prop), p.hash_cutoff(*$algo, prop), "algo: {}, t: {}", $id, $time.0); } } } } for time in times.iter() { for (id, algo, _props) in HASH_ALGO_MAP.iter() { // Second preimage resistance and collision resistance. check_hash!(id, algo, [ HashAlgoSecurity::SecondPreImageResistance, HashAlgoSecurity::CollisionResistance, ], time, format!( "[hash_algorithms] {} = \"{}\" ", id, time.0)); // Second preimage resistance. check_hash!(id, algo, [ HashAlgoSecurity::SecondPreImageResistance ], time, format!( "[hash_algorithms] {}.second_preimage_resistance = \"{}\" ", id, time.0)); // Collision resistance. check_hash!(id, algo, [ HashAlgoSecurity::CollisionResistance ], time, format!( "[hash_algorithms] {}.collision_resistance = \"{}\" ", id, time.0)); // Different ways of naming the key. check_hash!(id, algo, [ HashAlgoSecurity::CollisionResistance ], time, format!( "[hash_algorithms.{}] collision_resistance = \"{}\" ", id, time.0)); check_hash!(id, algo, [ HashAlgoSecurity::CollisionResistance ], time, format!( "hash_algorithms.{}.collision_resistance = \"{}\" ", id, time.0)); } } macro_rules! check { ($id:expr, $algo:expr, $time:expr, $config:expr, $get:ident) => { let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes($config).expect("valid"); let p = p.build(); assert_eq!(p.$get($algo.clone()), $time.1, "algo: {}, t: {}", $id, $time.0); } } for time in times.iter() { for (id, algo, _props) in ASYMM_ALGO_MAP.iter() { check!(id, algo, time, format!( "[asymmetric_algorithms] {} = \"{}\" ", id, time.0), asymmetric_algo_cutoff); } } for time in times.iter() { for (id, algo, _props) in SYMM_ALGO_MAP.iter() { check!(id, algo, time, format!( "[symmetric_algorithms] {} = \"{}\" ", id, time.0), symmetric_algo_cutoff); } } for time in times.iter() { for (id, algo, _props) in AEAD_ALGO_MAP.iter() { check!(id, algo, time, format!( "[aead_algorithms] {} = \"{}\" ", id, time.0), aead_algo_cutoff); } } for time in times.iter() { for (id, algo, props) in PACKET_MAP.into_iter() { // Unversioned. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(format!( "[packets] {} = \"{}\" ", id, time.0)).expect("valid"); let p = p.build(); let cutoff = p.packet_tag_version_cutoff(algo, 1); assert_eq!( cutoff, time.1, "algo: {}, t: {}", id, time.0); // Setting the default means it should apply to all // versions, including "unknown" versions. for version in props.into_iter().map(|(_id, v)| v) .chain(std::iter::once(&99)) { assert_eq!( p.packet_tag_version_cutoff(algo.clone(), *version), time.1, "algo: {}, version: {}, t: {}", id, version, time.0); } // Versioned. for (prop, version) in props { let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(format!( "[packets] {}.{} = \"{}\" ", id, prop, time.0)).expect("valid"); let p = p.build(); assert_eq!( p.packet_tag_version_cutoff( algo.clone(), *version), time.1, "algo: {}, version: {}, t: {}", id, *version, time.0); } } } Ok(()) } // Convenience function for using a timestamp. fn ts(t: &str) -> Option { parse_time(&Value::String(t.into())).expect("valid timestamp") } /// Check a simple config file. #[test] #[allow(deprecated)] fn simple_config() -> Result<()> { // Something simple. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[hash_algorithms] sha1 = \"always\" sha224 = 2017-03-04T13:25:35Z sha512.second_preimage_resistance = \"always\" sha512.collision_resistance = 2050-01-01 [symmetric_algorithms] cast5 = \"always\" aes128 = \"2040-01-01\" aes256 = \"2050-01-01\" ").expect("valid config"); let p = p.build(); assert_eq!( p.hash_cutoff(HashAlgorithm::SHA1, HashAlgoSecurity::SecondPreImageResistance), ts("always")); assert_eq!( p.hash_cutoff(HashAlgorithm::SHA224, HashAlgoSecurity::SecondPreImageResistance), ts("2017-03-04T13:25:35Z")); assert_eq!( p.hash_cutoff(HashAlgorithm::SHA512, HashAlgoSecurity::CollisionResistance), ts("2050-01-01")); assert_eq!( p.hash_cutoff(HashAlgorithm::SHA512, HashAlgoSecurity::SecondPreImageResistance), ts("always")); assert_eq!( p.symmetric_algo_cutoff(SymmetricAlgorithm::CAST5), ts("always")); assert_eq!( p.symmetric_algo_cutoff(SymmetricAlgorithm::AES128), ts("2040-01-01")); assert_eq!( p.symmetric_algo_cutoff(SymmetricAlgorithm::AES256), ts("2050-01-01")); Ok(()) } // Configure everything, then read it out again. #[test] fn all_config() -> Result<()> { let epoch = NaiveDate::from_ymd_opt(2020, 1, 1).expect("valid"); let mut d = epoch; let mut date = || -> String { let s = d.format("%Y-%m-%d"); d = d.succ_opt().expect("valid"); s.to_string() }; let mut config = String::new(); config.push_str("[hash_algorithms]\n"); for (id, algo, _props) in HASH_ALGO_MAP { config.push_str( &format!("{} = {} # {}\n", id, date(), algo)); } config.push_str("\n[asymmetric_algorithms]\n"); for (id, algo, _props) in ASYMM_ALGO_MAP { config.push_str( &format!("{} = {} # {}\n", id, date(), algo)); } config.push_str("\n[symmetric_algorithms]\n"); for (id, algo, _props) in SYMM_ALGO_MAP { config.push_str( &format!("{} = {} # {}\n", id, date(), algo)); } config.push_str("\n[aead_algorithms]\n"); for (id, algo, _props) in AEAD_ALGO_MAP { config.push_str( &format!("{} = {} # {}\n", id, date(), algo)); } config.push_str("\n[packets]\n"); for (id, algo, _props) in PACKET_MAP { config.push_str( &format!("{} = {} # {}\n", id, date(), algo)); } let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(config.clone()) .expect(&format!("valid config: {}", config)); let p = p.build(); // Reset the date to the epoch. let mut d = epoch; let mut date = || -> String { let s = d.format("%Y-%m-%d"); d = d.succ_opt().expect("valid"); s.to_string() }; // Make sure everything we set was really set. for (_, algo, _) in HASH_ALGO_MAP { assert_eq!( p.hash_cutoff(algo, HashAlgoSecurity::SecondPreImageResistance), ts(&date())); } for (_, algo, _) in ASYMM_ALGO_MAP { assert_eq!(p.asymmetric_algo_cutoff(algo), ts(&date())); } for (_, algo, _) in SYMM_ALGO_MAP { assert_eq!(p.symmetric_algo_cutoff(algo), ts(&date())); } for (_, algo, _) in AEAD_ALGO_MAP { assert_eq!(p.aead_algo_cutoff(algo), ts(&date())); } for (_, algo, props) in PACKET_MAP { let d = ts(&date()); let cutoff = p.packet_tag_version_cutoff(algo, 1); assert_eq!(cutoff, d); // Setting the default means it should apply to all // versions, including "unknown" versions. for version in props.into_iter().map(|(_id, v)| v) .chain(std::iter::once(&99)) { assert_eq!( p.packet_tag_version_cutoff(algo, *version), d, "algo: {}, version: {}, t: {:?}", algo, version, d); } } Ok(()) } #[test] fn check_sig() -> Result<()> { let alice = testdata::file("alice-secret.asc"); let cert = Cert::from_bytes(alice).expect("valid cert"); let now = ts("2022-10-30").unwrap(); // Should be valid according to the standard policy. let sp = &StandardPolicy::at(now); let _cert = cert.with_policy(sp, None).expect("valid under standard policy"); // If SHA512 has no collision resistance, the cert is still valid. let mut p = ConfiguredStandardPolicy::at(now); p.parse_bytes(b"[hash_algorithms] sha512.collision_resistance = \"never\"") .expect(&format!("valid config")); let p = p.build(); let _cert = cert.with_policy(&p, None) .expect("valid under: SHA512 has no collision resistance"); // If SHA512 has no 2nd preimage resistance, the cert is not valid. let mut p = ConfiguredStandardPolicy::at(now); p.parse_bytes(b"[hash_algorithms] sha512.second_preimage_resistance = \"never\"") .expect(&format!("valid config")); let p = p.build(); let _cert = assert!( cert.with_policy(&p, None).is_err(), "invalid under: SHA512 has no 2nd preimage resistance"); // If SHA512's 2nd preimage resistance is cutoff, it should be // invalid. let mut p = ConfiguredStandardPolicy::at(now); p.parse_bytes(&format!("[hash_algorithms] sha512.second_preimage_resistance = 2022-10-24")) .expect(&format!("valid config")); let p = p.build(); let _cert = assert!( cert.with_policy(&p, None).is_err(), "should be invalid under: SHA512 2nd preimage resistance cut off"); // If SHA512's 2nd preimage resistance will be cutoff, it // should be invalid. let mut p = ConfiguredStandardPolicy::at(ts("2022-10-26").unwrap()); p.parse_bytes(&format!("[hash_algorithms] sha512.second_preimage_resistance = 2022-10-27")) .expect(&format!("valid config")); let p = p.build(); let _cert = cert.with_policy(&p, ts("2022-10-26")).expect( "valid under: SHA512 2nd preimage resistance not yet cut off"); let mut p = ConfiguredStandardPolicy::at(ts("2022-10-29").unwrap()); p.parse_bytes(&format!("[hash_algorithms] sha512.second_preimage_resistance = 2022-10-27")) .expect(&format!("valid config")); let p = p.build(); let _cert = assert!( cert.with_policy(&p, ts("2022-10-28")).is_err(), "invalid under: SHA512 2nd preimage resistance cut off"); Ok(()) } #[test] fn default_disposition() -> Result<()> { // Reject everything. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[hash_algorithms] default_disposition = \"never\" [asymmetric_algorithms] default_disposition = \"never\" [symmetric_algorithms] default_disposition = \"never\" [aead_algorithms] default_disposition = \"never\" [packets] default_disposition = \"never\" ").expect("valid config"); let p = p.build(); for algo in 0..=u8::MAX { assert_eq!( p.hash_cutoff(algo.into(), HashAlgoSecurity::CollisionResistance), Some(UNIX_EPOCH)); assert_eq!( p.hash_cutoff(algo.into(), HashAlgoSecurity::SecondPreImageResistance), Some(UNIX_EPOCH)); } for (_, algo, _) in ASYMM_ALGO_MAP { assert_eq!(p.asymmetric_algo_cutoff(algo), Some(UNIX_EPOCH)); } for algo in 0..=u8::MAX { assert_eq!(p.symmetric_algo_cutoff(algo.into()), Some(UNIX_EPOCH)); } for algo in 0..=u8::MAX { assert_eq!(p.aead_algo_cutoff(algo.into()), Some(UNIX_EPOCH)); } for algo in 0..=u8::MAX { let cutoff = p.packet_tag_version_cutoff(algo.into(), 1); assert_eq!(cutoff, Some(UNIX_EPOCH)); } for (_, algo, props) in PACKET_MAP { // Setting the default means it should apply to all // versions, including "unknown" versions. for version in props.into_iter().map(|(_id, v)| v) .chain(std::iter::once(&99)) { assert_eq!( p.packet_tag_version_cutoff(algo, *version), Some(UNIX_EPOCH), "algo: {}, version: {}", algo, version); } } let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[hash_algorithms] sha512.collision_resistance = 2050-01-01 default_disposition = \"never\" [asymmetric_algorithms] rsa1024 = \"always\" default_disposition = \"never\" [symmetric_algorithms] aes128 = \"2040-01-01\" aes256 = \"2050-01-01\" default_disposition = \"never\" [aead_algorithms] ocb = \"always\" default_disposition = \"never\" [packets] seip = \"always\" default_disposition = \"never\" ").expect("valid config"); let p = p.build(); for algo in 0..=u8::MAX { let algo: HashAlgorithm = algo.into(); if algo == HashAlgorithm::SHA512 { assert_eq!( p.hash_cutoff(algo.into(), HashAlgoSecurity::CollisionResistance), ts("2050-01-01")); } else { assert_eq!( p.hash_cutoff(algo, HashAlgoSecurity::CollisionResistance), NEVER); } assert_eq!( p.hash_cutoff(algo.into(), HashAlgoSecurity::SecondPreImageResistance), NEVER); } for (_, algo, _) in ASYMM_ALGO_MAP { match algo { AsymmetricAlgorithm::RSA1024 => assert_eq!(p.asymmetric_algo_cutoff(algo), ALWAYS), algo => assert_eq!(p.asymmetric_algo_cutoff(algo), NEVER), } } for algo in 0..=u8::MAX { let algo = SymmetricAlgorithm::from(algo); match algo { SymmetricAlgorithm::AES128 => assert_eq!(p.symmetric_algo_cutoff(algo), ts("2040-01-01")), SymmetricAlgorithm::AES256 => assert_eq!(p.symmetric_algo_cutoff(algo), ts("2050-01-01")), algo => assert_eq!(p.symmetric_algo_cutoff(algo), NEVER), } } for algo in 0..=u8::MAX { let algo = AEADAlgorithm::from(algo); if algo == AEADAlgorithm::OCB { assert_eq!(p.aead_algo_cutoff(algo), ALWAYS); } else { assert_eq!(p.aead_algo_cutoff(algo), NEVER); } } for algo in 0..=u8::MAX { let algo = Tag::from(algo); let cutoff = p.packet_tag_version_cutoff(algo.into(), 1); if algo == Tag::SEIP { assert_eq!(cutoff, ALWAYS); } else { assert_eq!(cutoff, NEVER); } } for (_, algo, props) in PACKET_MAP { // Setting the default means it should apply to all // versions, including "unknown" versions. for version in props.into_iter().map(|(_id, v)| v) .chain(std::iter::once(&99)) { let cutoff = p.packet_tag_version_cutoff(algo, *version); if algo == Tag::SEIP { assert_eq!(cutoff, ALWAYS); } else { assert_eq!(cutoff, NEVER); } } } Ok(()) } // A string type can also be written as `key.default_disposition`. #[test] fn default_key() -> Result<()> { // Make sure `key` is the same as `key.default_disposition`: let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[hash_algorithms] sha512.default_disposition = 2050-01-01 [symmetric_algorithms] aes128.default_disposition = \"2040-01-01\" [aead_algorithms] ocb.default_disposition = \"always\" default_disposition = \"never\" ").expect("valid config"); let p = p.build(); assert_eq!( p.hash_cutoff(HashAlgorithm::SHA512, HashAlgoSecurity::CollisionResistance), ts("2050-01-01")); assert_eq!( p.hash_cutoff(HashAlgorithm::SHA512, HashAlgoSecurity::SecondPreImageResistance), ts("2050-01-01")); assert_eq!( p.symmetric_algo_cutoff(SymmetricAlgorithm::AES128), ts("2040-01-01")); assert_eq!( p.aead_algo_cutoff(AEADAlgorithm::OCB), ts("always")); assert_eq!( p.aead_algo_cutoff(AEADAlgorithm::EAX), ts("never")); // `key` is a string type, which is used as a map with an // invalid key. let mut p = ConfiguredStandardPolicy::new(); assert!(p.parse_bytes(b"[symmetric_algorithms] aes128.foo = \"2040-01-01\"").is_err()); // `key` is a string type, which is used as a map with an // invalid key, which is in ignore_invalid. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[symmetric_algorithms] aes256.foo = \"2040-01-01\" aes256.ignore_invalid = \"foo\" ").expect("valid config"); let p = p.build(); let sp = &StandardPolicy::new(); assert_eq!( p.symmetric_algo_cutoff(SymmetricAlgorithm::AES256), sp.symmetric_algo_cutoff(SymmetricAlgorithm::AES256)); // `key` is a string type, which is used as a map with an // invalid key, which is in ignore_invalid, and there is a // default_disposition key. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[symmetric_algorithms] aes256.foo = \"2040-01-01\" aes256.default_disposition = \"2050-01-01\" aes256.ignore_invalid = \"foo\" ").expect("valid config"); let p = p.build(); assert_eq!( p.symmetric_algo_cutoff(SymmetricAlgorithm::AES256), ts("2050-01-01")); Ok(()) } #[test] fn unversioned_packets() -> Result<()> { let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[packets] signature = 2030-01-01 ").expect("valid config"); let p = p.build(); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 3), ts("2030-01-01")); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 4), ts("2030-01-01")); Ok(()) } #[test] fn versioned_packets() -> Result<()> { let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[packets] signature.v3 = 2010-01-01 signature.v4 = 2030-01-01 ").expect("valid config"); let p = p.build(); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 3), ts("2010-01-01")); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 4), ts("2030-01-01")); let mut p = ConfiguredStandardPolicy::new(); assert!(p.parse_bytes(b"[packets] signature.v9 = 2010-01-01 signature.v4 = 2030-01-01 ").is_err()); let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[packets] signature.v3 = 2010-01-01 signature.v9 = 2010-01-01 signature.ignore_invalid = \"v9\" signature.v4 = 2030-01-01 ").expect("valid config"); let p = p.build(); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 3), ts("2010-01-01")); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 4), ts("2030-01-01")); // Use a default and override it for one version where the // override is less than the default. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[packets] signature.default_disposition = 2030-01-01 signature.v3 = 2010-01-01 ").expect("valid config"); let p = p.build(); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 3), ts("2010-01-01")); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 4), ts("2030-01-01")); // Use a default and override it for one version where the // override is greater than the default. let mut p = ConfiguredStandardPolicy::new(); p.parse_bytes(b"[packets] signature.default_disposition = 2030-01-01 signature.v3 = 2040-01-01 ").expect("valid config"); let p = p.build(); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 3), ts("2040-01-01")); assert_eq!( p.packet_tag_version_cutoff(Tag::Signature, 4), ts("2030-01-01")); Ok(()) } } sequoia-policy-config-0.8.1/src/testdata.rs000064400000000000000000000023511046102023000170070ustar 00000000000000//! Test data. //! //! This module includes the test data from `tests/data` in a //! structured way. #![allow(unused)] use std::fmt; use std::collections::BTreeMap; use std::path::PathBuf; use std::sync::OnceLock; pub struct Test { path: &'static str, pub bytes: &'static [u8], } impl fmt::Display for Test { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "tests/data/{}", self.path) } } #[allow(unused)] pub fn dir() -> PathBuf { PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/data")) } /// Returns the content of the given file below `keystore/tests/data`. pub fn file(name: &str) -> &'static [u8] { static FILES: OnceLock> = OnceLock::new(); FILES.get_or_init(|| { let mut m: BTreeMap<&'static str, &'static [u8]> = Default::default(); macro_rules! add { ( $key: expr, $path: expr ) => { m.insert($key, include_bytes!($path)) } } include!(concat!(env!("OUT_DIR"), "/tests.index.rs.inc")); // Sanity checks. assert!(m.contains_key("alice-secret.asc")); m }).get(name).unwrap_or_else(|| panic!("No such file {:?}", name)) } sequoia-policy-config-0.8.1/tests/check.rs000064400000000000000000000044751046102023000166370ustar 00000000000000use std::env::current_dir; use sequoia_openpgp as openpgp; use openpgp::Result; use assert_cmd::Command; // use predicates::prelude::*; #[test] fn bad_config() -> Result<()> { let cwd = current_dir()?; println!("The current directory is {}", cwd.display()); let mut cmd = Command::cargo_bin("sequoia-policy-config-check")?; let assert = cmd.arg("tests/config/bad.toml") .assert(); assert.failure(); Ok(()) } #[test] fn good_config() -> Result<()> { let cwd = current_dir()?; println!("The current directory is {}", cwd.display()); let mut cmd = Command::cargo_bin("sequoia-policy-config-check")?; let assert = cmd.arg("tests/config/good.toml") .assert(); assert.success(); Ok(()) } #[test] fn bad_config_env() -> Result<()> { let cwd = current_dir()?; println!("The current directory is {}", cwd.display()); let mut cmd = Command::cargo_bin("sequoia-policy-config-check")?; let cmd = cmd.env( "SEQUOIA_CRYPTO_POLICY", format!("{}/{}", cwd.display(), "tests/config/bad.toml")); let assert = cmd.assert(); assert.failure(); Ok(()) } #[test] fn good_config_env() -> Result<()> { let cwd = current_dir()?; println!("The current directory is {}", cwd.display()); let mut cmd = Command::cargo_bin("sequoia-policy-config-check")?; let cmd = cmd.env( "SEQUOIA_CRYPTO_POLICY", format!("{}/{}", cwd.display(), "tests/config/good.toml")); let assert = cmd.assert(); assert.success(); Ok(()) } // If no configuration is supplied, this will just read the default // configuration. #[test] fn no_args() -> Result<()> { let mut cmd = Command::cargo_bin("sequoia-policy-config-check")?; // Make the default config a no-op in case the system // configuration is bad. cmd.env("SEQUOIA_CRYPTO_POLICY", ""); let assert = cmd.assert(); assert.success(); Ok(()) } // Using a relative path in "SEQUOIA_CRYPTO_POLICY" is not allowed. #[test] fn relative_path_env() -> Result<()> { let cwd = current_dir()?; println!("The current directory is {}", cwd.display()); let mut cmd = Command::cargo_bin("sequoia-policy-config-check")?; let cmd = cmd.env( "SEQUOIA_CRYPTO_POLICY", "tests/config/good.toml"); let assert = cmd.assert(); assert.failure(); Ok(()) } sequoia-policy-config-0.8.1/tests/config/bad.toml000064400000000000000000000000621046102023000200700ustar 00000000000000[hash_algorithms] sha1 = "always" sha42 = "never" sequoia-policy-config-0.8.1/tests/config/good.toml000064400000000000000000000000421046102023000202700ustar 00000000000000[hash_algorithms] sha1 = "always" sequoia-policy-config-0.8.1/tests/data/alice-secret.asc000064400000000000000000000016041046102023000211440ustar 00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: 7B2D 9926 16FD 0088 6A83 1154 2F92 5915 9C83 38C1 Comment: Alice xVgEY1aAWBYJKwYBBAHaRw8BAQdA9Tg2NuCoA8QYEvjBuGLzxXPNzd7PyKg2vG5b JJkBlGMAAQDYOh3Is4tC0g7iMWkC7Gf0y2h94VB9UmgBRwJqC1Qc2Q49wsALBB8W CgB9BYJjVoBYAwsJBwkQL5JZFZyDOMFHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu c2VxdW9pYS1wZ3Aub3JnxH3auv+f9ubvVPzyAH+B8afVL+Rf4pARSJGVpAZaQowD FQoIApsBAh4BFiEEey2ZJhb9AIhqgxFUL5JZFZyDOMEAAAP3AQDwX256ji+JmFmw K0gJqYk5Su6QsHGjaHniplTjiEsaBQEA8n9FB7Sj465lwJ91WuToXAKkedpNoP86 K1PYxWmNswPNGUFsaWNlIDxhbGljZUBleGFtcGxlLm9yZz7CwA4EExYKAIAFgmNW gFgDCwkHCRAvklkVnIM4wUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lh LXBncC5vcmc6yIpZHwZmJ/qczU/BFHlentZHUM9rdHUUO+4aQ/uC4AMVCggCmQEC mwECHgEWIQR7LZkmFv0AiGqDEVQvklkVnIM4wQAA0RUA/08n5I8nU6lLHPZU7QNO 0Cx0dhnPXliCVmNvorXPYd8BAP9cMGitLMXgT4CIKDSfhh3h/Z4TgOt0rEvtU8JG Fb3RCw== =loDe -----END PGP PRIVATE KEY BLOCK-----