tests(feat): Complete rewrite of letsencrypt tests (#2286)

* chore: Normalize container setup

Easier to grok what is different between configurations.

- Container name usage replaced with variable
- Volumes defined earlier and redeclared when relevant (only real difference is `VOLUME_LETSENCRYPT`)
- Contextual comment about the `acme.json` copy.
- Quoting `SSL_TYPE`, `SSL_DOMAIN` and `-h` values for syntax highlighting.
- Moved `-t` and `${NAME}` to separate line.
- Consistent indentation.

* chore: DRY test logic

Extracts out repeated test logic into methods

* chore: Scope configs to individual test cases (1/3)

- Preparation step for shifting out the container configs to their own scoped test cases. Split into multiple commits to ease reviewing by diffs for this change.
- Re-arrange the hostname and domain configs to match the expected order of the new test cases.
- Shuffle the hostname and domainname grouped tests into tests per container config scope.
- Collapse the `acme.json` test cases into single test case.

* chore: Scope configs to individual test cases (2/3)

- Shifts the hostname and domainname container configs into their respective scoped test cases.
- Moving the `acme.json` container config produces a less favorable diff, so is deferred to a follow-up commit.
- Test cases updated to refer to their `${CONTAINER_NAME}` var instead of the hard-coded string name.

* chore: Scope configs to individual test cases (3/3)

Final commit to shift out the container configs.

- Common vars are exported in `setup_file()` for the test cases to use without needing to repeat the declaration in each test case.
- `teardown_file()` shifts container removal at end of scoped test case.

* chore: Adapt to `common_container_setup` template

- `CONTAINER_NAME` becomes `TEST_NAME` (`common.bash` helper via `init_with_defaults`).
- `docker run ...` and related configuration is now outsourced to the `common.bash` helper, only extra args that the default template does not cover are defined in the test case.
- `TARGET_DOMAIN`establishes the domain folder name for `/etc/letsencrypt/live`.
- `_should*` methods no longer manage a `CONTAINER_NAME` arg, instead using the `TEST_NAME` global that should be valid as test is run as a sequence of test cases.
- `PRIVATE_CONFIG` and the `private_config_path ...` are now using the global `TEST_TMP_CONFIG` initialized at the start of each test case, slightly different as not locally defined/scoped like `PRIVATE_CONFIG` would be within the test case, hence the explicit choice of a different name for context.

* chore: Minor tweaks

- Test case comment descriptions.
- DRY: `docker rm -f` lines moved to `teardown()`
- Use `wait_for_service` helper instead of checking the `changedetector` script itself is running.
- There is a startup delay before the `changedetector` begins monitoring, wait until it ready event is logged.
- Added a helper to query logs for a service (useful later).
- `/bin/sh` commands reduced to `sh`.
- Change the config check to match and compare output, not number of lines returned. Provides better failure output by bats to debug against.

* chore: Add more test functions for `acme.json`

This just extracts out existing logic from the test case to functions to make the test case itself more readable/terse.

* chore: Housekeeping

No changes, just moving logic around and grouping into inline functions, with some added comments.

* chore: Switch to `example.test` certs

This also required copying the source files to match the expected letsencrypt file structure expected in the test/container usage.

* chore: Delete `test/config/letsencrypt/`

No longer necessary, using the `example.test/` certs instead.

These letsencrypt certs weren't for the domains they were used for, and of course long expired.

* chore: Housekeeping

Add more maintainer comments, rename some functions.

* tests: Expand `acme.json` extraction coverage

Finally able to add more test coverage! :)

- Two new methods to validate expected success/failure of extraction for a given FQDN.
- Added an RSA test prior to the wildcard to test a renewal simulation (just with different cert type).
- Added extra method to make sure we're detecting multiple successful change events, not just a previous logged success (false positive).

* tests: Refactor the negotiate_tls functionality

Covers all ports (except POP) and correctly tests against expected verification status with new `example.test` certs.

The `FQDN` var will be put to use in a follow-up commit.

* tests: Verify the certs contain the expected FQDNs

* chore: Extract TLS test methods into a separate helper script

Can be useful for other TLS tests to utilize.

* chore: Housekeeping

* chore: Fix test typo

There was a mismatch between the output and expected output between these two files "find key for" and "find key & cert for". Changed to "find key and/or cert for" to make the warning more clear that it's issued for either or both failure conditions.

Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
This commit is contained in:
Brennan Kinney 2021-11-17 04:00:16 +13:00 committed by GitHub
parent 584577787a
commit 7ca056852f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 431 additions and 529 deletions

View file

@ -163,7 +163,7 @@ function _extract_certs_from_acme
if [[ -z ${KEY} ]] || [[ -z ${CERT} ]]
then
_notify 'warn' "_extract_certs_from_acme | Unable to find key & cert for '${CERT_DOMAIN}' in '/etc/letsencrypt/acme.json'"
_notify 'warn' "_extract_certs_from_acme | Unable to find key and/or cert for '${CERT_DOMAIN}' in '/etc/letsencrypt/acme.json'"
return 1
fi

View file

@ -1,29 +0,0 @@
{
"le": {
"Account": {
"Email": "acme@admin.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:acme@admin.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/0123456789"
},
"PrivateKey": "YES",
"KeyType": "4096"
},
"Certificates": [
{
"domain": {
"main": "example.com",
"sans": ["*.example.com"]
},
"certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1RENDQWN5Z0F3SUJBZ0lKQU4vKzNMTVF2bnYxTUEwR0NTcUdTSWIzRFFFQkN3VUFNQkl4RURBT0JnTlYKQkFNTUIzUmxjM1F0WTJFd0hoY05NakF3TmpJNU1qQTFOVEl4V2hjTk1qQXdPREk0TWpBMU5USXhXakFXTVJRdwpFZ1lEVlFRRERBdGxlR0Z0Y0d4bExtTnZiVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DCmdnRUJBTDVVTmc3eWJyWG9DSW5teFErZjM4KytzTEVjZ0c2UDBYK2ZhSDExQnc0N1Z0K21mMXZsdEloN29qTzgKRGVYcUZ4c0dMM1MvWXF5dVhYMFRHSU9oL2Nzam52djFHRUwxVXgwWUNzeUZrdmZsYjhOdVNLVzUyVDBkblVxRgpaRndsZHlrQ3dIblF4bXdZWnhuWmpWRjJZT3IvS21HWnZPNWR4U1RzL3FEdVUwY3AzRkQ0ejJDQkVMTG16aXh2CmZPMkxnazFZbi9IOW1OTE5TS1FhaVNlQ3hJZDVDek5JbG1VSWZuTDB0dWMzbjJmTmlnanVQS09WMkgvN05WVFQKVHJpdVAzODRieDlXVExmWDI5Y24rSG80aEtCYXEydDFXbXoranNXaTFneWExS3JMQU00enpRSEkrdTZyMytqUwozUHNSVnMxY3N5TzJOQ1hxVm8vYnhxZTM4K3NDQXdFQUFhTTVNRGN3Q1FZRFZSMFRCQUl3QURBTEJnTlZIUThFCkJBTUNCZUF3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdJR0NDc0dBUVVGQndNQk1BMEdDU3FHU0liM0RRRUIKQ3dVQUE0SUJBUUFrbUhIVGFaOGhpU3RvQS9YWWpHWGtIVDVEQmpqT2hSbTNtbWRDRit4aGJVY2ovZnJ3QlluMAphcEFHZk5TR3ErUEpUZ1Zkc1pVQUMrc09meFJtZTNGalU1Z0Fla2VJRGpPUU1kMVZiZG1jSVd0bkorVHR6OTRGClFtNVY3RGY4a1ZrY3FFNlV2dlh5WDNZRUZqMi9md2I0aHh5eWwvZkFXbDVhY1dUTE5BMm1PS20vZk1oS2V6K2gKM1ZHaEtRNVpHUzBRdCtMZWEzbzdMV3M1ZEg1TGhTdnMzRmU5UFNkZHhhME5idHI0c2ZnZk9JUUpnbzJtQ3ZjaAp1NXpGcTdudkRxZHNtZFp3WU1JY2lucFBXSmdFb1FMSldVL2dXTDJZYSs1a0oxMzdzbVBjWVg3akRTeUJIbGtRCm9BWU9CNjVZbm9XeFZ1UXRLcUhXNmY4bnFEMW53RUJuCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM5ekNDQWQrZ0F3SUJBZ0lKQVAvNDFhc0srSTNCTUEwR0NTcUdTSWIzRFFFQkN3VUFNQkl4RURBT0JnTlYKQkFNTUIzUmxjM1F0WTJFd0hoY05NakF3TmpJNU1qQTFOVEl4V2hjTk1qQXdPREk0TWpBMU5USXhXakFTTVJBdwpEZ1lEVlFRRERBZDBaWE4wTFdOaE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCmt6bE9GM1E4d3Q2RzhNOENnKy9VQURsa2JPVW5CbGJDd2xSbnFTcnZyWDdCUmMzN1IxWStLenNNbUdna1BrdkUKY3padVdiT1FVOGdoblFKd1NIVC9BSzFnNWpNYzdtWkxTa0UrdVZNb3I0KzRWZ3Q0a0t2Zmt0emNDSk9mby9xTApYVjJlUFJnVmxIaitwZWlscUhNTThQMDNWUHg2a3E3b1pFMXBCbGg0UXlMejdEWWNQNkFEM0JxL0hTTTVobXZQCmlIYkNIeTZ5ZitRc3VCcWFXQ2VjMXlnYzlHUG55RFhRb0RSQXdsY0EwYVZTU29zYzZIZVZRb0RCUFR6WlVyaU0KcmlxUEszWVQ0TEdFSDZuVHgzUlV0anVHOFpkR3pwZ3V3OS95MHRjY3Q3NzdXTEZJZXVCUWttWmlNRzNYZWl2dQpUYmZIQ2JxSkNPNTNmc2JLMENyekVRSURBUUFCbzFBd1RqQWRCZ05WSFE0RUZnUVV4bzZOWFJpMzlReEpuWlpECnZieGNvK20yVTdZd0h3WURWUjBqQkJnd0ZvQVV4bzZOWFJpMzlReEpuWlpEdmJ4Y28rbTJVN1l3REFZRFZSMFQKQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBT0JLTUcyYWFaK2YyR2F6ZHRxNytJbFJNM1lGdgppbkY1dWFaM2JxQytwS0RiMXdaSkx6V2dIVmdOU0dYZXRIUEthOVFweVFxRWUvYllNSzdhdkpvLy9GbWhnMCszClN3STJnOUJvSVBCZDRqSUJZNDFoL3pyeVRZNFBMeC9OcWFwV1I0LzNuRFBKM1NTTUhaNEpnUDhHVFhsem1GNmoKNFVnd1JyTEZRZDBaWllORFJvOGJaZVVFcVg3MGswRXFZOVF4QmpKZ1V6VnlXWWpQKy9TZVhBQkp5UHY3bHpSTgpudktqM0Y5MWVOZnFmOFkrV2RkdkI4am4zTFhvazRTaUZ6eEVTZkozblZPZ3dwOFNQaGhUU2hiWFFhajQ4Rng4Cm82VEdNOXV0UHROOXFJTnd2cXlySzRsVXdLajZZTHlUa1YxMG9WZ3RKWWh5eUhWVmw3SmhjOFVJTXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"key": "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBdmxRMkR2SnV0ZWdJaWViRkQ1L2Z6NzZ3c1J5QWJvL1JmNTlvZlhVSERqdFczNlovClcrVzBpSHVpTTd3TjVlb1hHd1l2ZEw5aXJLNWRmUk1ZZzZIOXl5T2UrL1VZUXZWVEhSZ0t6SVdTOStWdncyNUkKcGJuWlBSMmRTb1ZrWENWM0tRTEFlZERHYkJobkdkbU5VWFpnNnY4cVlabTg3bDNGSk96K29PNVRSeW5jVVBqUApZSUVRc3ViT0xHOTg3WXVDVFZpZjhmMlkwczFJcEJxSko0TEVoM2tMTTBpV1pRaCtjdlMyNXplZlo4MktDTzQ4Cm81WFlmL3MxVk5OT3VLNC9memh2SDFaTXQ5ZmIxeWY0ZWppRW9GcXJhM1ZhYlA2T3hhTFdESnJVcXNzQXpqUE4KQWNqNjdxdmY2TkxjK3hGV3pWeXpJN1kwSmVwV2o5dkdwN2Z6NndJREFRQUJBb0lCQVFDdWZoNGhqZm9hSStUUQpLUlk1d09VOFhTTTQvVnh5QU1DZE5OUmpVTXRyTE5QMHIzek1EOGgzNklGSTFQd1k4WWpGYWVKUU1yYVFnanVMCjA5b0J0SjR0Z3piYTRGV2g3YkNKVitWdXBIZWRkbWdFMERNaVhVVGhWeWxCalJINXVRK0tOYytvM3ROTGZ3UG4KR3lFSXNuTWdmMWVucTM4Zk9qRG9MYTgwYzhzOXpYaEh0Wng5SlF6RFViUXIrRE5UUzBSTFA1Mk1JL3BYR0MrZwpUMjI1c1ZWMzl1cVFGY2NIRUNhY0xEYlllNUVoelJpMlBOQTk4Zkh0Ty9sQVA5amp2UWlNY2NyMEtqanpFSGxTCmxvRnMxL3kvdkNBby9rVGhxaEtMLzBUM3FkaUcrWU5zbmUrVGh5Mnh4NVczN1lNR0l0ZTlmKzV5bVRtYitsZ2IKZlU2L2kydGhBb0dCQVBPNlVydDUwaDN2SjJtLytNRkNrb2tjYTE5NWs5c1lPMVJNa1RZSFBaNW40K25UdTMybwpSREt1L0t3T2dseTljcDAwUW44WEljRGk3TXV0OE1LN1JHdjFXeVpWbGJYMStMMzFGVCtjL045NnJIQmE1U0hJCm5oZFRMQkxQVG1iNk9PUFNXWEVIbDAwdnNsdEFsdXRJcnVmanpvd0V0Z3B0T2hZTzhhNjA4aWh2QW9HQkFNZnAKa2l1LzBibDdjUWdZZmdmSWZ5YzJpTU9aU0RseVRFRThxZmhWa1NWNFg3bDNycXk3eUNQNEc1MXBaQ1dWcDl6WQo4UzNtYmlDM3hYVjZpTzVQeGVoS1ZmdnFySXF6MnpaWDhTRjFhMUwzekRGQ3BFNkdmUHB5Uk1uK01hLy84b3haCmRwdGV6WlRCMVJtUDd6UndIVGJrSXhjU3NuYkVUOWNuZDc1ck9OSkZBb0dCQU0wQm0xZFFONW13TU5HMWhQSmkKSWNtc212QTYzbEE2eUtTMnBxbndXemNqb2NScnNWZ1hzZzJEdk1xb2hhU21RWUxUazE4OVFNbnkxa1RZY1J3SwowcG1RVG5Rbkp2OWYvek1ndEJmRzM3akdnY2NiM1lHV01zdmh6TCtobWd2cVN2SHVYQWRENEZNdlhIRi9HYktjCmQycGI1cjlGc3kyQUJJekxVeVNsMU02SEFvR0FCQUxneHZYelhGaG92VFBZbTRsZlc4Y1JXWE5pNnB3cmdZZVoKRlgyS0N3bHVTa2RuZnRuSnUwY0lMdEZsakFlRHRiKzRueVluZ1lxT2NMd0RzVnh5YVNYTXNlQlVrL2ZsNXlJKwptV0JFeGdabzEzZ3gyYzJEQm5keWYrY1UwaVk5bEtsYTR1VTFGTTRLMjVkeXdrZVpubmRYYU9nY0lwdnZ5aTVsCmpiR1RFMDBDZ1lBVCtVTm9tcDhKbW01YXFDME1kc050OW13T0tMVnRDazFZei9YODVQbVNpU1p4eG11cThVNXUKYThvYUovTm1tTXBZc1JHOXB5NW1JZ0RXSDFicnlPWlA3YVB0T0lWWnBZSDc3cU1ySjR2RmJ6MkphQTFiMWlySgoyMkhkajFYRDdMdjJ1cXQ3UVVsYU5RY3VrSkZJSE94WVJOWUNobEpuSUVmMmU3MGpkbEN4TGc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=",
"Store": "default"
}
]
}
}

View file

@ -1,35 +0,0 @@
{
"empty": {
"Account": null,
"Certificates": null
},
"le": {
"Account": {
"Email": "acme@admin.com",
"Registration": {
"body": {
"status": "valid",
"contact": [
"mailto:acme@admin.com"
]
},
"uri": "https://acme-v02.api.letsencrypt.org/acme/acct/0123456789"
},
"PrivateKey": "YES",
"KeyType": "4096"
},
"Certificates": [
{
"domain": {
"main": "mail.my-domain.com",
"sans": [
"mail2.my-domain.com"
]
},
"certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZHVENDQkFHZ0F3SUJBZ0lTQTUwamo2QS9pbEV4TWxhNDFQd1NlanlCTUEwR0NTcUdTSWIzRFFFQkN3VUEKTUVveEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtFdzFNWlhRbmN5QkZibU55ZVhCME1TTXdJUVlEVlFRRApFeHBNWlhRbmN5QkZibU55ZVhCMElFRjFkR2h2Y21sMGVTQllNekFlRncweE5qQTBNVGt4T1RBMU1EQmFGdzB4Ck5qQTNNVGd4T1RBMU1EQmFNQlV4RXpBUkJnTlZCQU1UQ21sbWRYTnBieTVqYjIwd2dnRWlNQTBHQ1NxR1NJYjMKRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDY0NsZitQZWUxRUl0ZG5qYWdPVVF1d0E0U0xMaUtDZjVUKzJFYwpCUG53TUdLdERiL1RCV2M4S0VIUUd4WUNkdGFtRmNpVCtPWFVsSkdqUEdFbmE0REFLQU5pNW5qbXErVFFGYjdKCmlwQTdwZlE0ZnAvMk9xRzNlNlN3TnZXdXJKbEhJaWdpTGUxbGJjKzdydC81aG9uN0p3bjI2MHgvWGFQSFhSa1UKQWl5NUZTRFZlWG5uQ0w1UU91NXNybkhyZFRsV3BFbno5V1V2WUNqM0RNUjM4Z3hvam5tcGo0OGFNUlJ0ckJBTwpObHhUOVRzc0hvS3ZEWEkxYkViZWIydHBtQy8ra1JQdXNJdWtpdWNjM0ZvOVIvc0hYakZrRDdtSzJVTWIwVUxFCkJHMkQ0d3dFSU5VU0czQjN3c3UwZXl3QWxrcFgxVWNGemRGVHRzalU3VjJhMDZqQkFnTUJBQUdqZ2dJc01JSUMKS0RBT0JnTlZIUThCQWY4RUJBTUNCYUF3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQwpNQXdHQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZPS3FSbktUZDJhZFdEK1NuZFNaVkZQc0xWSmtNQjhHCkExVWRJd1FZTUJhQUZLaEthbU1FZmQyNjV0RTV0NlpGWmUvenFPeWhNSEFHQ0NzR0FRVUZCd0VCQkdRd1lqQXYKQmdnckJnRUZCUWN3QVlZamFIUjBjRG92TDI5amMzQXVhVzUwTFhnekxteGxkSE5sYm1OeWVYQjBMbTl5Wnk4dwpMd1lJS3dZQkJRVUhNQUtHSTJoMGRIQTZMeTlqWlhKMExtbHVkQzE0TXk1c1pYUnpaVzVqY25sd2RDNXZjbWN2Ck1EWUdBMVVkRVFRdk1DMkNDbWxtZFhOcGJ5NWpiMjJDRDIxaGFXd3VhV1oxYzJsdkxtTnZiWUlPZDNkM0xtbG0KZFhOcGJ5NWpiMjB3Z2Y0R0ExVWRJQVNCOWpDQjh6QUlCZ1puZ1F3QkFnRXdnZVlHQ3lzR0FRUUJndDhUQVFFQgpNSUhXTUNZR0NDc0dBUVVGQndJQkZocG9kSFJ3T2k4dlkzQnpMbXhsZEhObGJtTnllWEIwTG05eVp6Q0Jxd1lJCkt3WUJCUVVIQWdJd2daNE1nWnRVYUdseklFTmxjblJwWm1sallYUmxJRzFoZVNCdmJteDVJR0psSUhKbGJHbGwKWkNCMWNHOXVJR0o1SUZKbGJIbHBibWNnVUdGeWRHbGxjeUJoYm1RZ2IyNXNlU0JwYmlCaFkyTnZjbVJoYm1ObApJSGRwZEdnZ2RHaGxJRU5sY25ScFptbGpZWFJsSUZCdmJHbGplU0JtYjNWdVpDQmhkQ0JvZEhSd2N6b3ZMMnhsCmRITmxibU55ZVhCMExtOXlaeTl5WlhCdmMybDBiM0o1THpBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQWd6ZjkKRFZDZFZ0S3ZsbUdlVDJwdUhVNVVMZjN0L0pENk5MM29jdUJNc0RRUE9IeGE2a2t5ZDZ4cWRCQWVsTlNmRVl2KwpCVmZRcDZXb3gySUdyd2ZxcXZOTnpQR1RITHhTcEs5NEdrMGVlZzdZaGN4am9Pcnl2NEZnb3dRT2F4NUowT1NTCldJZEFGVnlrUHM4N1dLeUhOWThXMXpsZS9ZZTl5alM2YmpIZGpxbk9pRy83cURRL0REWUduN0lMSEFIbVVaWXkKMVFRMEVkZmZOa0xwa21DblRub3RnQlVwcW1EdDdwTU5aUnVZRlRRcTYzMWloZTdqUlhqU2tnV1M3dFRmVVQxNQpTZXNVSW8xTmJqQ0ptQmNlRmQyYy9zcmdWbGJXYzJMWHQ3UWY1eXhXSnloVDE2ci9NN29rMGJ0SDI1RDVhemsyClRLZG5xL1FGaEhXVlpVcjNoZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVrakNDQTNxZ0F3SUJBZ0lRQ2dGQlFnQUFBVk9GYzJvTGhleW5DREFOQmdrcWhraUc5dzBCQVFzRkFEQS8KTVNRd0lnWURWUVFLRXh0RWFXZHBkR0ZzSUZOcFoyNWhkSFZ5WlNCVWNuVnpkQ0JEYnk0eEZ6QVZCZ05WQkFNVApEa1JUVkNCU2IyOTBJRU5CSUZnek1CNFhEVEUyTURNeE56RTJOREEwTmxvWERUSXhNRE14TnpFMk5EQTBObG93ClNqRUxNQWtHQTFVRUJoTUNWVk14RmpBVUJnTlZCQW9URFV4bGRDZHpJRVZ1WTNKNWNIUXhJekFoQmdOVkJBTVQKR2t4bGRDZHpJRVZ1WTNKNWNIUWdRWFYwYUc5eWFYUjVJRmd6TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQwpBUThBTUlJQkNnS0NBUUVBbk5NTThGcmxMa2UzY2wwM2c3Tm9ZekRxMXpVbUdTWGh2YjQxOFhDU0w3ZTRTMEVGCnE2bWVOUWhZN0xFcXhHaUhDNlBqZGVUbTg2ZGljYnA1Z1dBZjE1R2FuL1BRZUdkeHlHa09sWkhQL3VhWjZXQTgKU014K3lrMTNFaVNkUnh0YTY3bnNIamNBSEp5c2U2Y0Y2czVLNjcxQjVUYVl1Y3Y5YlR5V2FOOGpLa0tRRElaMApaOGgvcFpxNFVtRVVFejlsNllLSHk5djZEbGIyaG9uemhUK1hocSt3M0JydmF3MlZGbjNFSzZCbHNwa0VObldBCmE2eEs4eHVRU1hndm9wWlBLaUFsS1FUR2RNRFFNYzJQTVRpVkZycW9NN2hEOGJFZnd6Qi9vbmt4RXowdE52amoKL1BJemFyazVNY1d2eEkwTkhXUVdNNnI2aENtMjFBdkEySDNEa3dJREFRQUJvNElCZlRDQ0FYa3dFZ1lEVlIwVApBUUgvQkFnd0JnRUIvd0lCQURBT0JnTlZIUThCQWY4RUJBTUNBWVl3ZndZSUt3WUJCUVVIQVFFRWN6QnhNRElHCkNDc0dBUVVGQnpBQmhpWm9kSFJ3T2k4dmFYTnlaeTUwY25WemRHbGtMbTlqYzNBdWFXUmxiblJ5ZFhOMExtTnYKYlRBN0JnZ3JCZ0VGQlFjd0FvWXZhSFIwY0RvdkwyRndjSE11YVdSbGJuUnlkWE4wTG1OdmJTOXliMjkwY3k5awpjM1J5YjI5MFkyRjRNeTV3TjJNd0h3WURWUjBqQkJnd0ZvQVV4S2V4cEhzc2NmcmI0VXVRZGYvRUZXQ0ZpUkF3ClZBWURWUjBnQkUwd1N6QUlCZ1puZ1F3QkFnRXdQd1lMS3dZQkJBR0MzeE1CQVFFd01EQXVCZ2dyQmdFRkJRY0MKQVJZaWFIUjBjRG92TDJOd2N5NXliMjkwTFhneExteGxkSE5sYm1OeWVYQjBMbTl5WnpBOEJnTlZIUjhFTlRBegpNREdnTDZBdGhpdG9kSFJ3T2k4dlkzSnNMbWxrWlc1MGNuVnpkQzVqYjIwdlJGTlVVazlQVkVOQldETkRVa3d1ClkzSnNNQjBHQTFVZERnUVdCQlNvU21wakJIM2R1dWJST2JlbVJXWHY4Nmpzb1RBTkJna3Foa2lHOXcwQkFRc0YKQUFPQ0FRRUEzVFBYRWZOaldEamRHQlg3Q1ZXK2RsYTVjRWlsYVVjbmU4SWtDSkx4V2g5S0VpazNKSFJSSEdKbwp1TTJWY0dmbDk2UzhUaWhSelp2b3JvZWQ2dGk2V3FFQm10enczV29kYXRnK1Z5T2VwaDRFWXByLzF3WEt0eDgvCndBcEl2SlN3dG1WaTRNRlU1YU1xclNERTZlYTczTWoydGNNeW81ak1kNmptZVdVSEs4c28vam9XVW9IT1Vnd3UKWDRQbzFRWXorM2RzemtEcU1wNGZrbHhCd1hSc1cxMEtYelBNVForc09QQXZleXhpbmRtamtXOGxHeStRc1JsRwpQZlorRzZaNmg3bWplbTBZK2lXbGtZY1Y0UElXTDFpd0JpOHNhQ2JHUzVqTjJwOE0rWCtRN1VOS0VrUk9iM042CktPcWtxbTU3VEgySDNlREpBa1NuaDYvRE5GdTBRZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=",
"key": "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQ2NDbGYrUGVlMUVJdGQKbmphZ09VUXV3QTRTTExpS0NmNVQrMkVjQlBud01HS3REYi9UQldjOEtFSFFHeFlDZHRhbUZjaVQrT1hVbEpHagpQR0VuYTREQUtBTmk1bmptcStUUUZiN0ppcEE3cGZRNGZwLzJPcUczZTZTd052V3VySmxISWlnaUxlMWxiYys3CnJ0LzVob243SnduMjYweC9YYVBIWFJrVUFpeTVGU0RWZVhubkNMNVFPdTVzcm5IcmRUbFdwRW56OVdVdllDajMKRE1SMzhneG9qbm1wajQ4YU1SUnRyQkFPTmx4VDlUc3NIb0t2RFhJMWJFYmViMnRwbUMvK2tSUHVzSXVraXVjYwozRm85Ui9zSFhqRmtEN21LMlVNYjBVTEVCRzJENHd3RUlOVVNHM0Izd3N1MGV5d0Fsa3BYMVVjRnpkRlR0c2pVCjdWMmEwNmpCQWdNQkFBRUNnZ0VBTStjQTQ5RmxqQVdIeGNrRmRILzMzUEVHL1NhZzcxRnBwamVjVW55WlFqcGwKNkJnRnNVUS8xWE95aUcwcUFnSFRYZ1VxNVlWSnRVOEJybUU4RTZlZmVNc1diVVFwL05nNlVMaWE4R0RGbndHUgpYV1ZKQWRiNHlaWTM3bUVwa1VOWjdKNUE2VFdMbkV4Tlo2bEFXTGhXbHhLaUx0NlBZR0llUXdjRmUzRkp2UG4wCkdVU0ZZWFlMSnE5bElpclF2bDZsVnpsanBQNnF2RlFFcWE0ZGdXcUJPckMyL2pMNGFtS0s3MU4yM3NGbnowc1EKVXFqUDcyYzdOcis0eE1PaHNHZXRWMW1ZZ1BxQW9SNVczWFpScURQZVo2ZjBGSjdMNXhHNjlZSmVvN01yWGhLbApOOWtMaGJHUi9GSDNJSGRvN3RSYjJvR21IRExOSmY5ei9tQkVlclNXMFFLQmdRRFBIQ2M1OXRDd21GMVVWNGVWCmZoUm9xNFF5cDh3RjJJdEpUTWQxMkxKT1g2N2VOSnk2djkzQWh1YVBnS3Ava1JNdWw1WmpMOTBVVjFJU2wvbHoKZVl6Z3JlTXR0Q3RSaFp4VVN2Qm82dzMyTlNhY29pS2Nab2p5VGR5WlB1T2VBRzJSeE5IaCtuK05aN05qSVd2Rwo3eGxXOUhYUU9QaTh4bEhwRGZEcys3RWdYUUtCZ1FEQTRBSmxvcjIyZEV4R3VET0xsTzBldCtUVmhFcnFYRlNaCkN0Um13c0wrWFRlU0t5bmdaY3l1MVlueW9OT0E5dkd5T2syNkFXK1dWOU45VTZyd1ZzOENWY3plZTVlS1BaSk4KeFFaalVvK2ZlcDN4SUZ2QnBnbmFkZnJvZHhqRDhYTXBIY2IwSS9aUklDWktxSVZ2OXErRnpFWHFFK0hzZkQzQgprQmZaOEdaenRRS0JnRVZTZHc2L3ZqcGR4Vjlsck13czEwZnhvTjRUckFhSTVKWTBUTTcxS1RseWJXV1MxcUxyCmRaM3JpV0NmQUhLU2JJazcwK3AvS3RDVUtiUnZpZDlNNEFxVUtXWXkyQTBCVzhJYkV6MEs4REZvdVBQVWtTRW8KY000cG9aenBuK1pTM2xuY055UWNaSFZBTUpzTnBMV0Jja25ZcVZaNHUwajBXSlpaUkRzT1E4dEJBb0dCQUsycApCSDkraUZJL1pHNUliQ0RCZHI2eDFOaHF4UWsvR095elU0c3kwVjgxajFPTWlhZ0NBTWxxZTBwNmcvVWFZNFNWCittWC81UGo1R3ZNODRpeUQvTitkWVZqdzd3RUpiekdXdEttNUxKZnJUMHBNV0ZHRHJsdUUzdVZ3Vmx3V2lobjcKTmFlY3VhdFJ4eWh4azdPNzZVNFBIdVFrQXNkckZpK3lEY2V0TEpJQkFvR0JBSkhVTXR0S1E5L3NjNkVZZ2R5bQp1OGhNaS9XR3J0NWVPT0FKMTdsWTUzZVJaTGNpN3MxbWZzV0lGOWIwTjUwaUU2MFNhRkFEUWlNUkFVdGtKWE5JCmE1NXFkcGFsVkhzQUU0V3doN25sS0xrYURFYXJ0eDVYMXFTVEZ3NGZUTXlLTk92ZWlnZ1EvaTlMWnBGeHN6MjIKM1YrN2pQSmFDTnlQYm1PZXZYR2hCRWpyCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=",
"Store": "default"
}
]
}
}

View file

@ -1,18 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC5DCCAcygAwIBAgIJAN/+3LMQvnv1MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
BAMMB3Rlc3QtY2EwHhcNMjAwNjI5MjA1NTIxWhcNMjAwODI4MjA1NTIxWjAWMRQw
EgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAL5UNg7ybrXoCInmxQ+f38++sLEcgG6P0X+faH11Bw47Vt+mf1vltIh7ojO8
DeXqFxsGL3S/YqyuXX0TGIOh/csjnvv1GEL1Ux0YCsyFkvflb8NuSKW52T0dnUqF
ZFwldykCwHnQxmwYZxnZjVF2YOr/KmGZvO5dxSTs/qDuU0cp3FD4z2CBELLmzixv
fO2Lgk1Yn/H9mNLNSKQaiSeCxId5CzNIlmUIfnL0tuc3n2fNigjuPKOV2H/7NVTT
TriuP384bx9WTLfX29cn+Ho4hKBaq2t1Wmz+jsWi1gya1KrLAM4zzQHI+u6r3+jS
3PsRVs1csyO2NCXqVo/bxqe38+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8E
BAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEB
CwUAA4IBAQAkmHHTaZ8hiStoA/XYjGXkHT5DBjjOhRm3mmdCF+xhbUcj/frwBYn0
apAGfNSGq+PJTgVdsZUAC+sOfxRme3FjU5gAekeIDjOQMd1VbdmcIWtnJ+Ttz94F
Qm5V7Df8kVkcqE6UvvXyX3YEFj2/fwb4hxyyl/fAWl5acWTLNA2mOKm/fMhKez+h
3VGhKQ5ZGS0Qt+Lea3o7LWs5dH5LhSvs3Fe9PSddxa0Nbtr4sfgfOIQJgo2mCvch
u5zFq7nvDqdsmdZwYMIcinpPWJgEoQLJWU/gWL2Ya+5kJ137smPcYX7jDSyBHlkQ
oAYOB65YnoWxVuQtKqHW6f8nqD1nwEBn
-----END CERTIFICATE-----

View file

@ -1,36 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIC5DCCAcygAwIBAgIJAN/+3LMQvnv1MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
BAMMB3Rlc3QtY2EwHhcNMjAwNjI5MjA1NTIxWhcNMjAwODI4MjA1NTIxWjAWMRQw
EgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAL5UNg7ybrXoCInmxQ+f38++sLEcgG6P0X+faH11Bw47Vt+mf1vltIh7ojO8
DeXqFxsGL3S/YqyuXX0TGIOh/csjnvv1GEL1Ux0YCsyFkvflb8NuSKW52T0dnUqF
ZFwldykCwHnQxmwYZxnZjVF2YOr/KmGZvO5dxSTs/qDuU0cp3FD4z2CBELLmzixv
fO2Lgk1Yn/H9mNLNSKQaiSeCxId5CzNIlmUIfnL0tuc3n2fNigjuPKOV2H/7NVTT
TriuP384bx9WTLfX29cn+Ho4hKBaq2t1Wmz+jsWi1gya1KrLAM4zzQHI+u6r3+jS
3PsRVs1csyO2NCXqVo/bxqe38+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8E
BAMCBeAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEB
CwUAA4IBAQAkmHHTaZ8hiStoA/XYjGXkHT5DBjjOhRm3mmdCF+xhbUcj/frwBYn0
apAGfNSGq+PJTgVdsZUAC+sOfxRme3FjU5gAekeIDjOQMd1VbdmcIWtnJ+Ttz94F
Qm5V7Df8kVkcqE6UvvXyX3YEFj2/fwb4hxyyl/fAWl5acWTLNA2mOKm/fMhKez+h
3VGhKQ5ZGS0Qt+Lea3o7LWs5dH5LhSvs3Fe9PSddxa0Nbtr4sfgfOIQJgo2mCvch
u5zFq7nvDqdsmdZwYMIcinpPWJgEoQLJWU/gWL2Ya+5kJ137smPcYX7jDSyBHlkQ
oAYOB65YnoWxVuQtKqHW6f8nqD1nwEBn
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIC9zCCAd+gAwIBAgIJAP/41asK+I3BMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
BAMMB3Rlc3QtY2EwHhcNMjAwNjI5MjA1NTIxWhcNMjAwODI4MjA1NTIxWjASMRAw
DgYDVQQDDAd0ZXN0LWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
kzlOF3Q8wt6G8M8Cg+/UADlkbOUnBlbCwlRnqSrvrX7BRc37R1Y+KzsMmGgkPkvE
czZuWbOQU8ghnQJwSHT/AK1g5jMc7mZLSkE+uVMor4+4Vgt4kKvfktzcCJOfo/qL
XV2ePRgVlHj+peilqHMM8P03VPx6kq7oZE1pBlh4QyLz7DYcP6AD3Bq/HSM5hmvP
iHbCHy6yf+QsuBqaWCec1ygc9GPnyDXQoDRAwlcA0aVSSosc6HeVQoDBPTzZUriM
riqPK3YT4LGEH6nTx3RUtjuG8ZdGzpguw9/y0tcct777WLFIeuBQkmZiMG3Xeivu
TbfHCbqJCO53fsbK0CrzEQIDAQABo1AwTjAdBgNVHQ4EFgQUxo6NXRi39QxJnZZD
vbxco+m2U7YwHwYDVR0jBBgwFoAUxo6NXRi39QxJnZZDvbxco+m2U7YwDAYDVR0T
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAOBKMG2aaZ+f2Gazdtq7+IlRM3YFv
inF5uaZ3bqC+pKDb1wZJLzWgHVgNSGXetHPKa9QpyQqEe/bYMK7avJo//Fmhg0+3
SwI2g9BoIPBd4jIBY41h/zryTY4PLx/NqapWR4/3nDPJ3SSMHZ4JgP8GTXlzmF6j
4UgwRrLFQd0ZZYNDRo8bZeUEqX70k0EqY9QxBjJgUzVyWYjP+/SeXABJyPv7lzRN
nvKj3F91eNfqf8Y+WddvB8jn3LXok4SiFzxESfJ3nVOgwp8SPhhTShbXQaj48Fx8
o6TGM9utPtN9qINwvqyrK4lUwKj6YLyTkV10oVgtJYhyyHVVl7Jhc8UIMw==
-----END CERTIFICATE-----

View file

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvlQ2DvJutegIiebFD5/fz76wsRyAbo/Rf59ofXUHDjtW36Z/
W+W0iHuiM7wN5eoXGwYvdL9irK5dfRMYg6H9yyOe+/UYQvVTHRgKzIWS9+Vvw25I
pbnZPR2dSoVkXCV3KQLAedDGbBhnGdmNUXZg6v8qYZm87l3FJOz+oO5TRyncUPjP
YIEQsubOLG987YuCTVif8f2Y0s1IpBqJJ4LEh3kLM0iWZQh+cvS25zefZ82KCO48
o5XYf/s1VNNOuK4/fzhvH1ZMt9fb1yf4ejiEoFqra3VabP6OxaLWDJrUqssAzjPN
Acj67qvf6NLc+xFWzVyzI7Y0JepWj9vGp7fz6wIDAQABAoIBAQCufh4hjfoaI+TQ
KRY5wOU8XSM4/VxyAMCdNNRjUMtrLNP0r3zMD8h36IFI1PwY8YjFaeJQMraQgjuL
09oBtJ4tgzba4FWh7bCJV+VupHeddmgE0DMiXUThVylBjRH5uQ+KNc+o3tNLfwPn
GyEIsnMgf1enq38fOjDoLa80c8s9zXhHtZx9JQzDUbQr+DNTS0RLP52MI/pXGC+g
T225sVV39uqQFccHECacLDbYe5EhzRi2PNA98fHtO/lAP9jjvQiMccr0KjjzEHlS
loFs1/y/vCAo/kThqhKL/0T3qdiG+YNsne+Thy2xx5W37YMGIte9f+5ymTmb+lgb
fU6/i2thAoGBAPO6Urt50h3vJ2m/+MFCkokca195k9sYO1RMkTYHPZ5n4+nTu32o
RDKu/KwOgly9cp00Qn8XIcDi7Mut8MK7RGv1WyZVlbX1+L31FT+c/N96rHBa5SHI
nhdTLBLPTmb6OOPSWXEHl00vsltAlutIrufjzowEtgptOhYO8a608ihvAoGBAMfp
kiu/0bl7cQgYfgfIfyc2iMOZSDlyTEE8qfhVkSV4X7l3rqy7yCP4G51pZCWVp9zY
8S3mbiC3xXV6iO5PxehKVfvqrIqz2zZX8SF1a1L3zDFCpE6GfPpyRMn+Ma//8oxZ
dptezZTB1RmP7zRwHTbkIxcSsnbET9cnd75rONJFAoGBAM0Bm1dQN5mwMNG1hPJi
IcmsmvA63lA6yKS2pqnwWzcjocRrsVgXsg2DvMqohaSmQYLTk189QMny1kTYcRwK
0pmQTnQnJv9f/zMgtBfG37jGgccb3YGWMsvhzL+hmgvqSvHuXAdD4FMvXHF/GbKc
d2pb5r9Fsy2ABIzLUySl1M6HAoGABALgxvXzXFhovTPYm4lfW8cRWXNi6pwrgYeZ
FX2KCwluSkdnftnJu0cILtFljAeDtb+4nyYngYqOcLwDsVxyaSXMseBUk/fl5yI+
mWBExgZo13gx2c2DBndyf+cU0iY9lKla4uU1FM4K25dywkeZnndXaOgcIpvvyi5l
jbGTE00CgYAT+UNomp8Jmm5aqC0MdsNt9mwOKLVtCk1Yz/X85PmSiSZxxmuq8U5u
a8oaJ/NmmMpYsRG9py5mIgDWH1bryOZP7aPtOIVZpYH77qMrJ4vFbz2JaA1b1irJ
22Hdj1XD7Lv2uqt7QUlaNQcukJFIHOxYRNYChlJnIEf2e70jdlCxLg==
-----END RSA PRIVATE KEY-----

View file

@ -1,30 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFGTCCBAGgAwIBAgISA50jj6A/ilExMla41PwSejyBMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA0MTkxOTA1MDBaFw0x
NjA3MTgxOTA1MDBaMBUxEzARBgNVBAMTCmlmdXNpby5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCcClf+Pee1EItdnjagOUQuwA4SLLiKCf5T+2Ec
BPnwMGKtDb/TBWc8KEHQGxYCdtamFciT+OXUlJGjPGEna4DAKANi5njmq+TQFb7J
ipA7pfQ4fp/2OqG3e6SwNvWurJlHIigiLe1lbc+7rt/5hon7Jwn260x/XaPHXRkU
Aiy5FSDVeXnnCL5QOu5srnHrdTlWpEnz9WUvYCj3DMR38gxojnmpj48aMRRtrBAO
NlxT9TssHoKvDXI1bEbeb2tpmC/+kRPusIukiucc3Fo9R/sHXjFkD7mK2UMb0ULE
BG2D4wwEINUSG3B3wsu0eywAlkpX1UcFzdFTtsjU7V2a06jBAgMBAAGjggIsMIIC
KDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOKqRnKTd2adWD+SndSZVFPsLVJkMB8G
A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQwYjAv
BggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
MDYGA1UdEQQvMC2CCmlmdXNpby5jb22CD21haWwuaWZ1c2lvLmNvbYIOd3d3Lmlm
dXNpby5jb20wgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEB
MIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYI
KwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGll
ZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNl
IHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xl
dHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAgzf9
DVCdVtKvlmGeT2puHU5ULf3t/JD6NL3ocuBMsDQPOHxa6kkyd6xqdBAelNSfEYv+
BVfQp6Wox2IGrwfqqvNNzPGTHLxSpK94Gk0eeg7YhcxjoOryv4FgowQOax5J0OSS
WIdAFVykPs87WKyHNY8W1zle/Ye9yjS6bjHdjqnOiG/7qDQ/DDYGn7ILHAHmUZYy
1QQ0EdffNkLpkmCnTnotgBUpqmDt7pMNZRuYFTQq631ihe7jRXjSkgWS7tTfUT15
SesUIo1NbjCJmBceFd2c/srgVlbWc2LXt7Qf5yxWJyhT16r/M7ok0btH25D5azk2
TKdnq/QFhHWVZUr3hg==
-----END CERTIFICATE-----

View file

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -1,57 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFGTCCBAGgAwIBAgISA50jj6A/ilExMla41PwSejyBMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA0MTkxOTA1MDBaFw0x
NjA3MTgxOTA1MDBaMBUxEzARBgNVBAMTCmlmdXNpby5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCcClf+Pee1EItdnjagOUQuwA4SLLiKCf5T+2Ec
BPnwMGKtDb/TBWc8KEHQGxYCdtamFciT+OXUlJGjPGEna4DAKANi5njmq+TQFb7J
ipA7pfQ4fp/2OqG3e6SwNvWurJlHIigiLe1lbc+7rt/5hon7Jwn260x/XaPHXRkU
Aiy5FSDVeXnnCL5QOu5srnHrdTlWpEnz9WUvYCj3DMR38gxojnmpj48aMRRtrBAO
NlxT9TssHoKvDXI1bEbeb2tpmC/+kRPusIukiucc3Fo9R/sHXjFkD7mK2UMb0ULE
BG2D4wwEINUSG3B3wsu0eywAlkpX1UcFzdFTtsjU7V2a06jBAgMBAAGjggIsMIIC
KDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOKqRnKTd2adWD+SndSZVFPsLVJkMB8G
A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQwYjAv
BggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
MDYGA1UdEQQvMC2CCmlmdXNpby5jb22CD21haWwuaWZ1c2lvLmNvbYIOd3d3Lmlm
dXNpby5jb20wgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEB
MIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYI
KwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGll
ZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNl
IHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xl
dHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAgzf9
DVCdVtKvlmGeT2puHU5ULf3t/JD6NL3ocuBMsDQPOHxa6kkyd6xqdBAelNSfEYv+
BVfQp6Wox2IGrwfqqvNNzPGTHLxSpK94Gk0eeg7YhcxjoOryv4FgowQOax5J0OSS
WIdAFVykPs87WKyHNY8W1zle/Ye9yjS6bjHdjqnOiG/7qDQ/DDYGn7ILHAHmUZYy
1QQ0EdffNkLpkmCnTnotgBUpqmDt7pMNZRuYFTQq631ihe7jRXjSkgWS7tTfUT15
SesUIo1NbjCJmBceFd2c/srgVlbWc2LXt7Qf5yxWJyhT16r/M7ok0btH25D5azk2
TKdnq/QFhHWVZUr3hg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCcClf+Pee1EItd
njagOUQuwA4SLLiKCf5T+2EcBPnwMGKtDb/TBWc8KEHQGxYCdtamFciT+OXUlJGj
PGEna4DAKANi5njmq+TQFb7JipA7pfQ4fp/2OqG3e6SwNvWurJlHIigiLe1lbc+7
rt/5hon7Jwn260x/XaPHXRkUAiy5FSDVeXnnCL5QOu5srnHrdTlWpEnz9WUvYCj3
DMR38gxojnmpj48aMRRtrBAONlxT9TssHoKvDXI1bEbeb2tpmC/+kRPusIukiucc
3Fo9R/sHXjFkD7mK2UMb0ULEBG2D4wwEINUSG3B3wsu0eywAlkpX1UcFzdFTtsjU
7V2a06jBAgMBAAECggEAM+cA49FljAWHxckFdH/33PEG/Sag71FppjecUnyZQjpl
6BgFsUQ/1XOyiG0qAgHTXgUq5YVJtU8BrmE8E6efeMsWbUQp/Ng6ULia8GDFnwGR
XWVJAdb4yZY37mEpkUNZ7J5A6TWLnExNZ6lAWLhWlxKiLt6PYGIeQwcFe3FJvPn0
GUSFYXYLJq9lIirQvl6lVzljpP6qvFQEqa4dgWqBOrC2/jL4amKK71N23sFnz0sQ
UqjP72c7Nr+4xMOhsGetV1mYgPqAoR5W3XZRqDPeZ6f0FJ7L5xG69YJeo7MrXhKl
N9kLhbGR/FH3IHdo7tRb2oGmHDLNJf9z/mBEerSW0QKBgQDPHCc59tCwmF1UV4eV
fhRoq4Qyp8wF2ItJTMd12LJOX67eNJy6v93AhuaPgKp/kRMul5ZjL90UV1ISl/lz
eYzgreMttCtRhZxUSvBo6w32NSacoiKcZojyTdyZPuOeAG2RxNHh+n+NZ7NjIWvG
7xlW9HXQOPi8xlHpDfDs+7EgXQKBgQDA4AJlor22dExGuDOLlO0et+TVhErqXFSZ
CtRmwsL+XTeSKyngZcyu1YnyoNOA9vGyOk26AW+WV9N9U6rwVs8CVczee5eKPZJN
xQZjUo+fep3xIFvBpgnadfrodxjD8XMpHcb0I/ZRICZKqIVv9q+FzEXqE+HsfD3B
kBfZ8GZztQKBgEVSdw6/vjpdxV9lrMws10fxoN4TrAaI5JY0TM71KTlybWWS1qLr
dZ3riWCfAHKSbIk70+p/KtCUKbRvid9M4AqUKWYy2A0BW8IbEz0K8DFouPPUkSEo
cM4poZzpn+ZS3lncNyQcZHVAMJsNpLWBcknYqVZ4u0j0WJZZRDsOQ8tBAoGBAK2p
BH9+iFI/ZG5IbCDBdr6x1NhqxQk/GOyzU4sy0V81j1OMiagCAMlqe0p6g/UaY4SV
+mX/5Pj5GvM84iyD/N+dYVjw7wEJbzGWtKm5LJfrT0pMWFGDrluE3uVwVlwWihn7
NaecuatRxyhxk7O76U4PHuQkAsdrFi+yDcetLJIBAoGBAJHUMttKQ9/sc6EYgdym
u8hMi/WGrt5eOOAJ17lY53eRZLci7s1mfsWIF9b0N50iE60SaFADQiMRAUtkJXNI
a55qdpalVHsAE4Wwh7nlKLkaDEartx5X1qSTFw4fTMyKNOveiggQ/i9LZpFxsz22
3V+7jPJaCNyPbmOevXGhBEjr
-----END PRIVATE KEY-----

View file

@ -1,30 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFGTCCBAGgAwIBAgISA50jj6A/ilExMla41PwSejyBMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA0MTkxOTA1MDBaFw0x
NjA3MTgxOTA1MDBaMBUxEzARBgNVBAMTCmlmdXNpby5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCcClf+Pee1EItdnjagOUQuwA4SLLiKCf5T+2Ec
BPnwMGKtDb/TBWc8KEHQGxYCdtamFciT+OXUlJGjPGEna4DAKANi5njmq+TQFb7J
ipA7pfQ4fp/2OqG3e6SwNvWurJlHIigiLe1lbc+7rt/5hon7Jwn260x/XaPHXRkU
Aiy5FSDVeXnnCL5QOu5srnHrdTlWpEnz9WUvYCj3DMR38gxojnmpj48aMRRtrBAO
NlxT9TssHoKvDXI1bEbeb2tpmC/+kRPusIukiucc3Fo9R/sHXjFkD7mK2UMb0ULE
BG2D4wwEINUSG3B3wsu0eywAlkpX1UcFzdFTtsjU7V2a06jBAgMBAAGjggIsMIIC
KDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOKqRnKTd2adWD+SndSZVFPsLVJkMB8G
A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQwYjAv
BggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
MDYGA1UdEQQvMC2CCmlmdXNpby5jb22CD21haWwuaWZ1c2lvLmNvbYIOd3d3Lmlm
dXNpby5jb20wgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEB
MIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYI
KwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGll
ZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNl
IHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xl
dHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAgzf9
DVCdVtKvlmGeT2puHU5ULf3t/JD6NL3ocuBMsDQPOHxa6kkyd6xqdBAelNSfEYv+
BVfQp6Wox2IGrwfqqvNNzPGTHLxSpK94Gk0eeg7YhcxjoOryv4FgowQOax5J0OSS
WIdAFVykPs87WKyHNY8W1zle/Ye9yjS6bjHdjqnOiG/7qDQ/DDYGn7ILHAHmUZYy
1QQ0EdffNkLpkmCnTnotgBUpqmDt7pMNZRuYFTQq631ihe7jRXjSkgWS7tTfUT15
SesUIo1NbjCJmBceFd2c/srgVlbWc2LXt7Qf5yxWJyhT16r/M7ok0btH25D5azk2
TKdnq/QFhHWVZUr3hg==
-----END CERTIFICATE-----

View file

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -1,57 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFGTCCBAGgAwIBAgISA50jj6A/ilExMla41PwSejyBMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA0MTkxOTA1MDBaFw0x
NjA3MTgxOTA1MDBaMBUxEzARBgNVBAMTCmlmdXNpby5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCcClf+Pee1EItdnjagOUQuwA4SLLiKCf5T+2Ec
BPnwMGKtDb/TBWc8KEHQGxYCdtamFciT+OXUlJGjPGEna4DAKANi5njmq+TQFb7J
ipA7pfQ4fp/2OqG3e6SwNvWurJlHIigiLe1lbc+7rt/5hon7Jwn260x/XaPHXRkU
Aiy5FSDVeXnnCL5QOu5srnHrdTlWpEnz9WUvYCj3DMR38gxojnmpj48aMRRtrBAO
NlxT9TssHoKvDXI1bEbeb2tpmC/+kRPusIukiucc3Fo9R/sHXjFkD7mK2UMb0ULE
BG2D4wwEINUSG3B3wsu0eywAlkpX1UcFzdFTtsjU7V2a06jBAgMBAAGjggIsMIIC
KDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFOKqRnKTd2adWD+SndSZVFPsLVJkMB8G
A1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMHAGCCsGAQUFBwEBBGQwYjAv
BggrBgEFBQcwAYYjaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8w
LwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcv
MDYGA1UdEQQvMC2CCmlmdXNpby5jb22CD21haWwuaWZ1c2lvLmNvbYIOd3d3Lmlm
dXNpby5jb20wgf4GA1UdIASB9jCB8zAIBgZngQwBAgEwgeYGCysGAQQBgt8TAQEB
MIHWMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCBqwYI
KwYBBQUHAgIwgZ4MgZtUaGlzIENlcnRpZmljYXRlIG1heSBvbmx5IGJlIHJlbGll
ZCB1cG9uIGJ5IFJlbHlpbmcgUGFydGllcyBhbmQgb25seSBpbiBhY2NvcmRhbmNl
IHdpdGggdGhlIENlcnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL2xl
dHNlbmNyeXB0Lm9yZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAgzf9
DVCdVtKvlmGeT2puHU5ULf3t/JD6NL3ocuBMsDQPOHxa6kkyd6xqdBAelNSfEYv+
BVfQp6Wox2IGrwfqqvNNzPGTHLxSpK94Gk0eeg7YhcxjoOryv4FgowQOax5J0OSS
WIdAFVykPs87WKyHNY8W1zle/Ye9yjS6bjHdjqnOiG/7qDQ/DDYGn7ILHAHmUZYy
1QQ0EdffNkLpkmCnTnotgBUpqmDt7pMNZRuYFTQq631ihe7jRXjSkgWS7tTfUT15
SesUIo1NbjCJmBceFd2c/srgVlbWc2LXt7Qf5yxWJyhT16r/M7ok0btH25D5azk2
TKdnq/QFhHWVZUr3hg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCcClf+Pee1EItd
njagOUQuwA4SLLiKCf5T+2EcBPnwMGKtDb/TBWc8KEHQGxYCdtamFciT+OXUlJGj
PGEna4DAKANi5njmq+TQFb7JipA7pfQ4fp/2OqG3e6SwNvWurJlHIigiLe1lbc+7
rt/5hon7Jwn260x/XaPHXRkUAiy5FSDVeXnnCL5QOu5srnHrdTlWpEnz9WUvYCj3
DMR38gxojnmpj48aMRRtrBAONlxT9TssHoKvDXI1bEbeb2tpmC/+kRPusIukiucc
3Fo9R/sHXjFkD7mK2UMb0ULEBG2D4wwEINUSG3B3wsu0eywAlkpX1UcFzdFTtsjU
7V2a06jBAgMBAAECggEAM+cA49FljAWHxckFdH/33PEG/Sag71FppjecUnyZQjpl
6BgFsUQ/1XOyiG0qAgHTXgUq5YVJtU8BrmE8E6efeMsWbUQp/Ng6ULia8GDFnwGR
XWVJAdb4yZY37mEpkUNZ7J5A6TWLnExNZ6lAWLhWlxKiLt6PYGIeQwcFe3FJvPn0
GUSFYXYLJq9lIirQvl6lVzljpP6qvFQEqa4dgWqBOrC2/jL4amKK71N23sFnz0sQ
UqjP72c7Nr+4xMOhsGetV1mYgPqAoR5W3XZRqDPeZ6f0FJ7L5xG69YJeo7MrXhKl
N9kLhbGR/FH3IHdo7tRb2oGmHDLNJf9z/mBEerSW0QKBgQDPHCc59tCwmF1UV4eV
fhRoq4Qyp8wF2ItJTMd12LJOX67eNJy6v93AhuaPgKp/kRMul5ZjL90UV1ISl/lz
eYzgreMttCtRhZxUSvBo6w32NSacoiKcZojyTdyZPuOeAG2RxNHh+n+NZ7NjIWvG
7xlW9HXQOPi8xlHpDfDs+7EgXQKBgQDA4AJlor22dExGuDOLlO0et+TVhErqXFSZ
CtRmwsL+XTeSKyngZcyu1YnyoNOA9vGyOk26AW+WV9N9U6rwVs8CVczee5eKPZJN
xQZjUo+fep3xIFvBpgnadfrodxjD8XMpHcb0I/ZRICZKqIVv9q+FzEXqE+HsfD3B
kBfZ8GZztQKBgEVSdw6/vjpdxV9lrMws10fxoN4TrAaI5JY0TM71KTlybWWS1qLr
dZ3riWCfAHKSbIk70+p/KtCUKbRvid9M4AqUKWYy2A0BW8IbEz0K8DFouPPUkSEo
cM4poZzpn+ZS3lncNyQcZHVAMJsNpLWBcknYqVZ4u0j0WJZZRDsOQ8tBAoGBAK2p
BH9+iFI/ZG5IbCDBdr6x1NhqxQk/GOyzU4sy0V81j1OMiagCAMlqe0p6g/UaY4SV
+mX/5Pj5GvM84iyD/N+dYVjw7wEJbzGWtKm5LJfrT0pMWFGDrluE3uVwVlwWihn7
NaecuatRxyhxk7O76U4PHuQkAsdrFi+yDcetLJIBAoGBAJHUMttKQ9/sc6EYgdym
u8hMi/WGrt5eOOAJ17lY53eRZLci7s1mfsWIF9b0N50iE60SaFADQiMRAUtkJXNI
a55qdpalVHsAE4Wwh7nlKLkaDEartx5X1qSTFw4fTMyKNOveiggQ/i9LZpFxsz22
3V+7jPJaCNyPbmOevXGhBEjr
-----END PRIVATE KEY-----

View file

@ -1,133 +1,331 @@
load 'test_helper/common'
load 'test_helper/tls'
# Globals referenced from `test_helper/common`:
# TEST_NAME TEST_FQDN TEST_TMP_CONFIG
# Requires maintenance (TODO): Yes
# Can run tests in parallel?: No
# Not parallelize friendly when TEST_NAME is static,
# presently name of test file: `mail_ssl_letsencrypt`.
#
# Also shares a common TEST_TMP_CONFIG local folder,
# Instead of individual PRIVATE_CONFIG copies.
# For this test that is a non-issue, unless run in parallel.
# Applies to all tests:
function setup_file() {
init_with_defaults
# Override default to match the hostname we want to test against instead:
export TEST_FQDN='mail.example.test'
# Prepare certificates in the letsencrypt supported file structure:
# Note Certbot uses `privkey.pem`.
# `fullchain.pem` is currently what's detected, but we're actually providing the equivalent of `cert.pem` here.
# TODO: Verify format/structure is supported for nginx-proxy + acme-companion (uses `acme.sh` to provision).
# `mail.example.test` (Only this FQDN is supported by this certificate):
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/cert.ecdsa.pem' 'mail.example.test/fullchain.pem'
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/key.ecdsa.pem' "mail.example.test/privkey.pem"
# `example.test` (Only this FQDN is supported by this certificate):
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/cert.rsa.pem' 'example.test/fullchain.pem'
_copy_to_letsencrypt_storage 'example.test/with_ca/ecdsa/key.rsa.pem' 'example.test/privkey.pem'
}
# Not used
# function teardown_file() {
# }
# Applies per test:
function setup() {
run_setup_file_if_necessary
}
function teardown() {
docker rm -f "${TEST_NAME}"
run_teardown_file_if_necessary
}
function setup_file() {
local PRIVATE_CONFIG
PRIVATE_CONFIG="$(duplicate_config_for_container . mail_lets_domain)"
docker run -d --name mail_lets_domain \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-v "${PRIVATE_CONFIG}/letsencrypt/my-domain.com":/etc/letsencrypt/live/my-domain.com \
-e DMS_DEBUG=0 \
-e SSL_TYPE=letsencrypt \
-h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_lets_domain
PRIVATE_CONFIG="$(duplicate_config_for_container . mail_lets_hostname)"
docker run -d --name mail_lets_hostname \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-v "${PRIVATE_CONFIG}/letsencrypt/mail.my-domain.com":/etc/letsencrypt/live/mail.my-domain.com \
-e DMS_DEBUG=0 \
-e SSL_TYPE=letsencrypt \
-h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_lets_hostname
PRIVATE_CONFIG="$(duplicate_config_for_container . mail_lets_acme_json)"
cp "$(private_config_path mail_lets_acme_json)/letsencrypt/acme.json" "$(private_config_path mail_lets_acme_json)/acme.json"
docker run -d --name mail_lets_acme_json \
-v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \
-v "${PRIVATE_CONFIG}/acme.json":/etc/letsencrypt/acme.json:ro \
-v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \
-e DMS_DEBUG=1 \
-e SSL_TYPE=letsencrypt \
-e "SSL_DOMAIN=*.example.com" \
-h mail.my-domain.com -t "${NAME}"
wait_for_finished_setup_in_container mail_lets_acme_json
}
function teardown_file() {
docker rm -f mail_lets_domain
docker rm -f mail_lets_hostname
docker rm -f mail_lets_acme_json
}
# this test must come first to reliably identify when to run setup_file
@test "first" {
skip 'Starting testing of letsencrypt SSL'
}
@test "checking ssl: letsencrypt configuration is correct" {
#test domain has certificate files
run docker exec mail_lets_domain /bin/sh -c 'postconf | grep "smtpd_tls_chain_files = /etc/letsencrypt/live/my-domain.com/key.pem /etc/letsencrypt/live/my-domain.com/fullchain.pem" | wc -l'
assert_success
assert_output 1
run docker exec mail_lets_domain /bin/sh -c 'doveconf | grep "ssl_cert = </etc/letsencrypt/live/my-domain.com/fullchain.pem" | wc -l'
assert_success
assert_output 1
run docker exec mail_lets_domain /bin/sh -c 'doveconf -P | grep "ssl_key = </etc/letsencrypt/live/my-domain.com/key.pem" | wc -l'
assert_success
assert_output 1
# Should detect and choose the cert for FQDN `mail.example.test` (HOSTNAME):
@test "ssl(letsencrypt): Should default to HOSTNAME (mail.example.test)" {
local TARGET_DOMAIN='mail.example.test'
local TEST_DOCKER_ARGS=(
--volume "${TEST_TMP_CONFIG}/letsencrypt/${TARGET_DOMAIN}/:/etc/letsencrypt/live/${TARGET_DOMAIN}/:ro"
--env SSL_TYPE='letsencrypt'
)
common_container_setup 'TEST_DOCKER_ARGS'
#test hostname has certificate files
run docker exec mail_lets_hostname /bin/sh -c 'postconf | grep "smtpd_tls_chain_files = /etc/letsencrypt/live/mail.my-domain.com/privkey.pem /etc/letsencrypt/live/mail.my-domain.com/fullchain.pem" | wc -l'
assert_success
assert_output 1
run docker exec mail_lets_hostname /bin/sh -c 'doveconf | grep "ssl_cert = </etc/letsencrypt/live/mail.my-domain.com/fullchain.pem" | wc -l'
assert_success
assert_output 1
run docker exec mail_lets_hostname /bin/sh -c 'doveconf -P | grep "ssl_key = </etc/letsencrypt/live/mail.my-domain.com/privkey.pem" | wc -l'
assert_success
assert_output 1
_should_have_valid_config "${TARGET_DOMAIN}" 'privkey.pem' 'fullchain.pem'
_should_succesfully_negotiate_tls "${TARGET_DOMAIN}"
_should_not_have_fqdn_in_cert 'example.test'
}
@test "checking ssl: letsencrypt cert works correctly" {
run docker exec mail_lets_domain /bin/sh -c "timeout 1 openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ | grep 'Verify return code: 10 (certificate has expired)'"
assert_success
run docker exec mail_lets_domain /bin/sh -c "timeout 1 openssl s_client -connect 0.0.0.0:465 -CApath /etc/ssl/certs/ | grep 'Verify return code: 10 (certificate has expired)'"
assert_success
run docker exec mail_lets_hostname /bin/sh -c "timeout 1 openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ | grep 'Verify return code: 10 (certificate has expired)'"
assert_success
run docker exec mail_lets_hostname /bin/sh -c "timeout 1 openssl s_client -connect 0.0.0.0:465 -CApath /etc/ssl/certs/ | grep 'Verify return code: 10 (certificate has expired)'"
assert_success
# Should detect and choose cert for FQDN `example.test` (DOMAINNAME),
# as fallback when no cert for FQDN `mail.example.test` (HOSTNAME) exists:
@test "ssl(letsencrypt): Should fallback to DOMAINNAME (example.test)" {
local TARGET_DOMAIN='example.test'
local TEST_DOCKER_ARGS=(
--volume "${TEST_TMP_CONFIG}/letsencrypt/${TARGET_DOMAIN}/:/etc/letsencrypt/live/${TARGET_DOMAIN}/:ro"
--env SSL_TYPE='letsencrypt'
)
common_container_setup 'TEST_DOCKER_ARGS'
#test domain has certificate files
_should_have_valid_config "${TARGET_DOMAIN}" 'privkey.pem' 'fullchain.pem'
_should_succesfully_negotiate_tls "${TARGET_DOMAIN}"
_should_not_have_fqdn_in_cert 'mail.example.test'
}
# When using `acme.json` (Traefik) - a wildcard cert `*.example.test` (SSL_DOMAIN)
# should be extracted and be chosen over an existing FQDN `mail.example.test` (HOSTNAME):
# _acme_wildcard should verify the FQDN `mail.example.test` is negotiated, not `example.test`.
#
# acme.json updates
#
# NOTE: Currently all of the `acme.json` configs have the FQDN match a SAN value,
# all Subject CN (`main` in acme.json) are `Smallstep Leaf` which is not an FQDN.
# While valid for that field, it does mean there is no test coverage against `main`.
@test "ssl(letsencrypt): Traefik 'acme.json' (*.example.test)" {
# This test group changes to certs signed with an RSA Root CA key,
# These certs all support both FQDNs: `mail.example.test` and `example.test`,
# Except for the wildcard cert `*.example.test`, which should not support `example.test`.
# We want to maintain the same FQDN (mail.example.test) between the _acme_ecdsa and _acme_rsa tests.
local LOCAL_BASE_PATH="${PWD}/test/test-files/ssl/example.test/with_ca/rsa"
@test "checking changedetector: server is ready" {
run docker exec mail_lets_acme_json /bin/bash -c "ps aux | grep '/bin/bash /usr/local/bin/check-for-changes.sh'"
assert_success
}
# Change default Root CA cert used for verifying chain of trust with openssl:
# shellcheck disable=SC2034
local TEST_CA_CERT="${TEST_FILES_CONTAINER_PATH}/ssl/example.test/with_ca/rsa/ca-cert.rsa.pem"
@test "can extract certs from acme.json" {
run docker exec mail_lets_acme_json /bin/bash -c "cat /etc/letsencrypt/live/mail.my-domain.com/key.pem"
assert_output "$(cat "$(private_config_path mail_lets_acme_json)/letsencrypt/mail.my-domain.com/privkey.pem")"
assert_success
function _prepare() {
# Default `acme.json` for _acme_ecdsa test:
cp "${LOCAL_BASE_PATH}/ecdsa.acme.json" "${TEST_TMP_CONFIG}/letsencrypt/acme.json"
run docker exec mail_lets_acme_json /bin/bash -c "cat /etc/letsencrypt/live/mail.my-domain.com/fullchain.pem"
assert_output "$(cat "$(private_config_path mail_lets_acme_json)/letsencrypt/mail.my-domain.com/fullchain.pem")"
assert_success
}
# TODO: Provision wildcard certs via Traefik to inspect if `example.test` non-wildcard is also added to the cert.
# `DMS_DEBUG=1` required for catching logged `inf` output.
# shellcheck disable=SC2034
local TEST_DOCKER_ARGS=(
--volume "${TEST_TMP_CONFIG}/letsencrypt/acme.json:/etc/letsencrypt/acme.json:ro"
--env SSL_TYPE='letsencrypt'
--env SSL_DOMAIN='*.example.test'
--env DMS_DEBUG=1
)
@test "can detect changes" {
cp "$(private_config_path mail_lets_acme_json)/letsencrypt/acme-changed.json" "$(private_config_path mail_lets_acme_json)/acme.json"
sleep 11
run docker exec mail_lets_acme_json /bin/bash -c "supervisorctl tail changedetector"
assert_output --partial "postfix: stopped"
assert_output --partial "postfix: started"
assert_output --partial "Change detected"
common_container_setup 'TEST_DOCKER_ARGS'
wait_for_service "${TEST_NAME}" 'changedetector'
run docker exec mail_lets_acme_json /bin/bash -c "cat /etc/letsencrypt/live/example.com/key.pem"
assert_output "$(cat "$(private_config_path mail_lets_acme_json)/letsencrypt/changed/key.pem")"
assert_success
# Wait until the changedetector service startup delay is over:
repeat_until_success_or_timeout 20 sh -c "$(_get_service_logs 'changedetector') | grep 'check-for-changes is ready'"
}
run docker exec mail_lets_acme_json /bin/bash -c "cat /etc/letsencrypt/live/example.com/fullchain.pem"
assert_output "$(cat "$(private_config_path mail_lets_acme_json)/letsencrypt/changed/fullchain.pem")"
assert_success
# Test `acme.json` extraction works at container startup:
# It should have already extracted `mail.example.test` from the original mounted `acme.json`.
function _acme_ecdsa() {
_should_have_succeeded_at_extraction 'mail.example.test'
# SSL_DOMAIN set as ENV, but startup should not have match in `acme.json`:
_should_have_failed_at_extraction '*.example.test' 'mailserver'
_should_have_valid_config 'mail.example.test' 'key.pem' 'fullchain.pem'
local ECDSA_KEY_PATH="${LOCAL_BASE_PATH}/key.ecdsa.pem"
local ECDSA_CERT_PATH="${LOCAL_BASE_PATH}/cert.ecdsa.pem"
_should_have_expected_files 'mail.example.test' "${ECDSA_KEY_PATH}" "${ECDSA_CERT_PATH}"
}
# Test `acme.json` extraction is triggered via change detection:
# The updated `acme.json` roughly emulates a renewal, but changes from an ECDSA cert to an RSA one.
# It should replace the cert files in the existing `letsencrypt/live/mail.example.test/` folder.
function _acme_rsa() {
_should_extract_on_changes 'mail.example.test' "${LOCAL_BASE_PATH}/rsa.acme.json"
_should_have_service_restart_count '1'
local RSA_KEY_PATH="${LOCAL_BASE_PATH}/key.rsa.pem"
local RSA_CERT_PATH="${LOCAL_BASE_PATH}/cert.rsa.pem"
_should_have_expected_files 'mail.example.test' "${RSA_KEY_PATH}" "${RSA_CERT_PATH}"
}
# Test that `acme.json` also works with wildcard certificates:
# Additionally tests that SSL_DOMAIN is prioritized when `letsencrypt/live/` already has a HOSTNAME dir available.
# Wildcard `*.example.test` should extract to `example.test/` in `letsencrypt/live/`:
function _acme_wildcard() {
_should_extract_on_changes 'example.test' "${LOCAL_BASE_PATH}/wildcard/rsa.acme.json"
_should_have_service_restart_count '2'
# TODO: Make this pass.
# As the FQDN has changed since startup, the configs need to be updated accordingly.
# This requires the `changedetector` service event to invoke the same function for TLS configuration
# that is used during container startup to work correctly. A follow up PR will refactor `setup-stack.sh` for supporting this.
# _should_have_valid_config 'example.test' 'key.pem' 'fullchain.pem'
local WILDCARD_KEY_PATH="${LOCAL_BASE_PATH}/wildcard/key.rsa.pem"
local WILDCARD_CERT_PATH="${LOCAL_BASE_PATH}/wildcard/cert.rsa.pem"
_should_have_expected_files 'example.test' "${WILDCARD_KEY_PATH}" "${WILDCARD_CERT_PATH}"
# Verify this works for wildcard certs, it should use `*.example.test` for `mail.example.test` (NOT `example.test`):
_should_succesfully_negotiate_tls 'mail.example.test'
# WARNING: This should fail...but requires resolving the above TODO.
# _should_not_have_fqdn_in_cert 'example.test'
}
_prepare
# Unleash the `acme.json` tests!
# NOTE: Test failures aren't as helpful here as bats will only identify function calls at this top-level,
# rather than the actual failing nested function call..
# TODO: Extract methods to separate test cases.
_acme_ecdsa
_acme_rsa
_acme_wildcard
}
# this test is only there to reliably mark the end for the teardown_file
# this test is only there to reliably mark the end for the teardown_file
@test "last" {
skip 'Finished testing of letsencrypt SSL'
}
#
# Test Methods
#
# Check that Dovecot and Postfix are configured to use a cert for the expected FQDN:
function _should_have_valid_config() {
local EXPECTED_FQDN=${1}
local LE_KEY_PATH="/etc/letsencrypt/live/${EXPECTED_FQDN}/${2}"
local LE_CERT_PATH="/etc/letsencrypt/live/${EXPECTED_FQDN}/${3}"
_has_matching_line 'postconf' "smtpd_tls_chain_files = ${LE_KEY_PATH} ${LE_CERT_PATH}"
_has_matching_line 'doveconf' "ssl_cert = <${LE_CERT_PATH}"
# `-P` is required to prevent redacting secrets
_has_matching_line 'doveconf -P' "ssl_key = <${LE_KEY_PATH}"
}
# CMD ${1} run in container with output checked to match value of ${2}:
function _has_matching_line() {
run docker exec "${TEST_NAME}" sh -c "${1} | grep '${2}'"
assert_output "${2}"
}
#
# Traefik `acme.json` specific
#
# It should log success of extraction for the expected domain and restart Postfix.
function _should_have_succeeded_at_extraction() {
local EXPECTED_DOMAIN=${1}
local SERVICE=${2}
run $(_get_service_logs "${SERVICE}")
assert_output --partial "_extract_certs_from_acme | Certificate successfully extracted for '${EXPECTED_DOMAIN}'"
}
function _should_have_failed_at_extraction() {
local EXPECTED_DOMAIN=${1}
local SERVICE=${2}
run $(_get_service_logs "${SERVICE}")
assert_output --partial "_extract_certs_from_acme | Unable to find key and/or cert for '${EXPECTED_DOMAIN}' in '/etc/letsencrypt/acme.json'"
}
# Replace the mounted `acme.json` and wait to see if changes were detected.
function _should_extract_on_changes() {
local EXPECTED_DOMAIN=${1}
local ACME_JSON=${2}
cp "${ACME_JSON}" "${TEST_TMP_CONFIG}/letsencrypt/acme.json"
# Change detection takes a little over 5 seconds to complete (restart services)
sleep 10
# Expected log lines from the changedetector service:
run $(_get_service_logs 'changedetector')
assert_output --partial 'Change detected'
assert_output --partial "'/etc/letsencrypt/acme.json' has changed, extracting certs"
assert_output --partial "_extract_certs_from_acme | Certificate successfully extracted for '${EXPECTED_DOMAIN}'"
assert_output --partial 'Restarting services due to detected changes'
assert_output --partial 'postfix: stopped'
assert_output --partial 'postfix: started'
assert_output --partial 'dovecot: stopped'
assert_output --partial 'dovecot: started'
}
# Ensure change detection is not mistakenly validating against previous change events:
function _should_have_service_restart_count() {
local NUM_RESTARTS=${1}
# Count how many times postfix was restarted by the `changedetector` service:
run docker exec "${TEST_NAME}" sh -c "supervisorctl tail changedetector | grep -c 'postfix: started'"
assert_output "${NUM_RESTARTS}"
}
# Extracted cert files from `acme.json` have content matching the expected reference files:
function _should_have_expected_files() {
local LE_BASE_PATH="/etc/letsencrypt/live/${1}"
local LE_KEY_PATH="${LE_BASE_PATH}/key.pem"
local LE_CERT_PATH="${LE_BASE_PATH}/fullchain.pem"
local EXPECTED_KEY_PATH=${2}
local EXPECTED_CERT_PATH=${3}
_should_be_equal_in_content "${LE_KEY_PATH}" "${EXPECTED_KEY_PATH}"
_should_be_equal_in_content "${LE_CERT_PATH}" "${EXPECTED_CERT_PATH}"
}
#
# Misc
#
# Rename test certificate files to match the expected file structure for letsencrypt:
function _copy_to_letsencrypt_storage() {
local SRC=${1}
local DEST=${2}
local FQDN_DIR
FQDN_DIR=$(echo "${DEST}" | cut -d '/' -f1)
mkdir -p "${TEST_TMP_CONFIG}/letsencrypt/${FQDN_DIR}"
cp "${PWD}/test/test-files/ssl/${SRC}" "${TEST_TMP_CONFIG}/letsencrypt/${DEST}"
}
function _should_be_equal_in_content() {
local CONTAINER_PATH=${1}
local LOCAL_PATH=${2}
run docker exec "${TEST_NAME}" sh -c "cat ${CONTAINER_PATH}"
assert_output "$(cat "${LOCAL_PATH}")"
assert_success
}
function _get_service_logs() {
local SERVICE=${1:-'mailserver'}
local CMD_LOGS=(docker exec "${TEST_NAME}" "supervisorctl tail ${SERVICE}")
# As the `mailserver` service logs are not stored in a file but output to stdout/stderr,
# The `supervisorctl tail` command won't work; we must instead query via `docker logs`:
if [[ ${SERVICE} == 'mailserver' ]]
then
CMD_LOGS=(docker logs "${TEST_NAME}")
fi
echo "${CMD_LOGS[@]}"
}

133
test/test_helper/tls.bash Normal file
View file

@ -0,0 +1,133 @@
#! /bin/bash
load 'test_helper/common'
# Helper methods for testing TLS.
# `_should_*` methods are useful for common high-level functionality.
# ? --------------------------------------------- Negotiate TLS
# For certs actually provisioned from LetsEncrypt the Root CA cert should not need to be provided,
# as it would already be available by default in `/etc/ssl/certs`, requiring only the cert chain (fullchain.pem).
function _should_succesfully_negotiate_tls() {
local FQDN=${1}
local CONTAINER_NAME=${2:-${TEST_NAME}}
# shellcheck disable=SC2031
local CA_CERT=${3:-${TEST_CA_CERT}}
# Postfix and Dovecot are ready:
wait_for_smtp_port_in_container_to_respond "${CONTAINER_NAME}"
wait_for_tcp_port_in_container 993 "${CONTAINER_NAME}"
# Root CA cert should be present in the container:
assert docker exec "${CONTAINER_NAME}" [ -f "${CA_CERT}" ]
local PORTS=(25 587 465 143 993)
for PORT in "${PORTS[@]}"
do
_negotiate_tls "${FQDN}" "${PORT}"
done
}
# Basically runs commands like:
# docker exec "${TEST_NAME}" sh -c "timeout 1 openssl s_client -connect localhost:587 -starttls smtp -CAfile ${CA_CERT} 2>/dev/null | grep 'Verification'"
function _negotiate_tls() {
local FQDN=${1}
local PORT=${2}
local CONTAINER_NAME=${3:-${TEST_NAME}}
# shellcheck disable=SC2031
local CA_CERT=${4:-${TEST_CA_CERT}}
local CMD_OPENSSL_VERIFY
CMD_OPENSSL_VERIFY=$(_generate_openssl_cmd "${PORT}")
# Should fail as a chain of trust is required to verify successfully:
run docker exec "${CONTAINER_NAME}" sh -c "${CMD_OPENSSL_VERIFY}"
assert_output --partial 'Verification error: unable to verify the first certificate'
# Provide the Root CA cert for successful verification:
CMD_OPENSSL_VERIFY=$(_generate_openssl_cmd "${PORT}" "-CAfile ${CA_CERT}")
run docker exec "${CONTAINER_NAME}" sh -c "${CMD_OPENSSL_VERIFY}"
assert_output --partial 'Verification: OK'
_should_have_fqdn_in_cert "${FQDN}" "${PORT}"
}
function _generate_openssl_cmd() {
# Using a HOST of `localhost` will not have issues with `/etc/hosts` matching,
# since hostname may not be match correctly in `/etc/hosts` during tests when checking cert validity.
local HOST='localhost'
local PORT=${1}
local EXTRA_ARGS=${2}
# `echo '' | openssl ...` is a common approach for providing input to `openssl` command which waits on input to exit.
# While the command is still successful it does result with `500 5.5.2 Error: bad syntax` being included in the response.
# `timeout 1` instead of the empty echo pipe approach seems to work better instead.
local CMD_OPENSSL="timeout 1 openssl s_client -connect ${HOST}:${PORT}"
# STARTTLS ports need to add a hint:
if [[ ${PORT} =~ ^(25|587)$ ]]
then
CMD_OPENSSL="${CMD_OPENSSL} -starttls smtp"
elif [[ ${PORT} == 143 ]]
then
CMD_OPENSSL="${CMD_OPENSSL} -starttls imap"
elif [[ ${PORT} == 110 ]]
then
CMD_OPENSSL="${CMD_OPENSSL} -starttls pop3"
fi
# `2>/dev/null` prevents openssl interleaving output to stderr that shouldn't be captured:
echo "${CMD_OPENSSL} ${EXTRA_ARGS} 2>/dev/null"
}
# ? --------------------------------------------- Verify FQDN
function _should_have_fqdn_in_cert() {
local FQDN
FQDN=$(escape_fqdn "${1}")
_get_fqdns_for_cert "$@"
assert_output --regexp "Subject: CN = ${FQDN}|DNS:${FQDN}"
}
function _should_not_have_fqdn_in_cert() {
local FQDN
FQDN=$(escape_fqdn "${1}")
_get_fqdns_for_cert "$@"
refute_output --regexp "Subject: CN = ${FQDN}|DNS:${FQDN}"
}
# Escapes `*` and `.` so the FQDN literal can be used in regex queries
# `sed` will match those two chars and `\\&` says to prepend a `\` to the sed match (`&`)
function escape_fqdn() {
# shellcheck disable=SC2001
sed 's|[\*\.]|\\&|g' <<< "${1}"
}
function _get_fqdns_for_cert() {
local FQDN=${1}
local PORT=${2:-'25'}
local CONTAINER_NAME=${3:-${TEST_NAME}}
# shellcheck disable=SC2031
local CA_CERT=${4:-${TEST_CA_CERT}}
# `-servername` is for SNI, where the port may be for a service that serves multiple certs,
# and needs a specific FQDN to return the correct cert. Such as a reverse-proxy.
local EXTRA_ARGS="-servername ${FQDN} -CAfile ${CA_CERT}"
local CMD_OPENSSL_VERIFY
# eg: "timeout 1 openssl s_client -connect localhost:25 -starttls smtp ${EXTRA_ARGS} 2>/dev/null"
CMD_OPENSSL_VERIFY=$(_generate_openssl_cmd "${PORT}" "${EXTRA_ARGS}")
# Takes the result of the openssl output to return the x509 certificate,
# We then check that for any matching FQDN entries:
# main == `Subject CN = <FQDN>`, sans == `DNS:<FQDN>`
local CMD_FILTER_FQDN="openssl x509 -noout -text | grep -E 'Subject: CN = |DNS:'"
run docker exec "${CONTAINER_NAME}" sh -c "${CMD_OPENSSL_VERIFY} | ${CMD_FILTER_FQDN}"
}