Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
06e8463
PYTHON-5040 Regenerate test TLS certificates with Authority Key Ident…
blink1073 Jun 4, 2026
5d18323
PYTHON-5040 Use test/certificates/ certs for SSL test client
blink1073 Jun 4, 2026
618acb8
PYTHON-5040 Export TLS cert paths from integration_tests/run.sh
blink1073 Jun 4, 2026
c3f98f1
PYTHON-5040 Use test/certificates/ certs for SSL integration test server
blink1073 Jun 4, 2026
d107450
PYTHON-5040 Use test/certificates/ certs for Evergreen SSL test client
blink1073 Jun 4, 2026
d16eb87
PYTHON-5040 Fix KMS mock server TLS for Python 3.13
blink1073 Jun 4, 2026
ca0b746
PYTHON-5040 Fix x509 auth username and CRL revocation in test certs
blink1073 Jun 4, 2026
afd411c
PYTHON-5040 Fix CSFLE TLS certs and configure-env for Python 3.13
blink1073 Jun 5, 2026
7ebc4c0
PYTHON-5040 Fix CA keyUsage and remove issuer from leaf cert AKI
blink1073 Jun 5, 2026
d113796
PYTHON-5040 Remove cRLSign from CA keyUsage to fix macOS CERT_SUSPENDED
blink1073 Jun 5, 2026
9e070b4
PYTHON-5040 Use cryptography library to generate certs with AKI but n…
blink1073 Jun 8, 2026
35d9660
PYTHON-5040 Add OCSPNoCheck to leaf certs and fix CA basicConstraints…
blink1073 Jun 8, 2026
aa6ecaa
PYTHON-5040 Switch AKI to issuer form and add CA keyUsage
blink1073 Jun 8, 2026
8aed47c
PYTHON-5040 Use self-generated Drivers Testing CA and separate KMS se…
blink1073 Jun 9, 2026
a163db5
PYTHON-5040 Disable TLS revocation check on macOS for SSL tests
blink1073 Jun 9, 2026
b4418cf
PYTHON-5040 Use keyid-form AKI for Python 3.14 compatibility
blink1073 Jun 9, 2026
628d1ce
PYTHON-5040 Fix CSFLE_TLS_CERT_FILE to use server-kms.pem
blink1073 Jun 9, 2026
f043fbd
PYTHON-5040 Make CA basicConstraints critical, regenerate certs
blink1073 Jun 9, 2026
62bc84f
PYTHON-5040 Add keyUsage to CA cert, regenerate certs
blink1073 Jun 10, 2026
0e8e7de
PYTHON-5040 Add SKI to KMS leaf certs, remove from CA
blink1073 Jun 10, 2026
3d56e35
PYTHON-5040 Use PROTOCOL_TLS_CLIENT in http_post for Python 3.14
blink1073 Jun 10, 2026
061b94d
PYTHON-5040 Update README and add run_server.py comment
blink1073 Jun 10, 2026
7bd8417
PYTHON-5040 Fix mypy typing errors in synchro.py and gen-certs.py
blink1073 Jun 10, 2026
977db57
PYTHON-5040 Clarify comments about macOS SecTrust and cert env vars
blink1073 Jun 11, 2026
c8a4a94
PYTHON-5040 Only use PROTOCOL_TLS_CLIENT in http_post on macOS
blink1073 Jun 11, 2026
9f61537
PYTHON-5040 Use uv run with PEP 723 inline metadata in gen-certs.py
blink1073 Jun 11, 2026
75e49b3
PYTHON-5040 Fix Windows KMS cert failures: issuer-form AKI, win32 guard
blink1073 Jun 11, 2026
75bf0e4
PYTHON-5040 Define AKI/SKI on first use, pin cryptography>=44.0.0
blink1073 Jun 11, 2026
febdef9
PYTHON-5040 Remove keyUsage from CA cert to fix Windows signature fai…
blink1073 Jun 11, 2026
b0219c1
PYTHON-5040 Switch to upstream drivers-evergreen-tools now that PR #7…
blink1073 Jun 11, 2026
afc448e
PYTHON-5040 Use create_default_context and clear X509_STRICT flag on …
blink1073 Jun 12, 2026
85c1802
PYTHON-5040 Update certificates README for keyUsage removal and VERIF…
blink1073 Jun 12, 2026
3d4fdb4
PYTHON-5040 Remove --tls-allow-invalid-certificates; update README wi…
blink1073 Jun 12, 2026
8442cec
PYTHON-5040 Rename KMS certs with kms- prefix for clarity
blink1073 Jun 12, 2026
3603e52
PYTHON-5040 Clarify that X509_V_FLAG_X509_STRICT is an OpenSSL flag s…
blink1073 Jun 13, 2026
f3f4d8b
PYTHON-5040 Add CA SKI, keyid-form AKI for KMS certs, restore macOS t…
blink1073 Jun 15, 2026
f95c1d4
PYTHON-5040 Add keyUsage to CA cert for Python 3.14 strict mode
blink1073 Jun 15, 2026
4abec61
PYTHON-5040 Trim gen-certs.py comments; refer to README for background
blink1073 Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .evergreen/scripts/run_server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import os
import sys
from typing import Any

from utils import DRIVERS_TOOLS, ROOT, get_test_options, run_command
Expand Down Expand Up @@ -42,6 +43,14 @@ def start_server():
set_env("TLS_CERT_KEY_FILE", certs / "client.pem")
set_env("TLS_PEM_KEY_FILE", certs / "server.pem")
set_env("TLS_CA_FILE", certs / "ca.pem")
if sys.platform == "darwin":
# MongoDB Enterprise on macOS uses Apple SecTrust with
# kSecRevocationRequirePositiveResponse, which requires a
# positive OCSP response for every cert in the chain. Our
# test CA is not in the macOS system keychain so OCSP always
# fails with CSSMERR_TP_CERT_SUSPENDED. Bypass cert
# verification to allow the server to start.
extra_opts.append("--tls-allow-invalid-certificates")

if opts.auth:
extra_opts.append("--auth")
Expand Down
20 changes: 16 additions & 4 deletions .evergreen/scripts/setup_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,10 +341,8 @@ def handle_test_env() -> None:
run_command(cmd, cwd=DRIVERS_TOOLS)

if SSL != "nossl":
if not DRIVERS_TOOLS:
raise RuntimeError("Missing DRIVERS_TOOLS")
write_env("CLIENT_PEM", f"{DRIVERS_TOOLS}/.evergreen/x509gen/client.pem")
write_env("CA_PEM", f"{DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem")
write_env("CLIENT_PEM", ROOT / "test/certificates/client.pem")
write_env("CA_PEM", ROOT / "test/certificates/ca.pem")

compressors = os.environ.get("COMPRESSORS") or opts.compressor
if compressors == "snappy":
Expand Down Expand Up @@ -382,6 +380,20 @@ def handle_test_env() -> None:
if not DRIVERS_TOOLS:
raise RuntimeError("Missing DRIVERS_TOOLS")
csfle_dir = Path(f"{DRIVERS_TOOLS}/.evergreen/csfle")

# Set CSFLE TLS cert paths to our AKI-enabled test/certificates/ before
# setup-secrets.sh runs. setup-secrets.sh uses ${VAR:-default} so
# pre-setting these vars causes them to flow into secrets-export.sh via
# csfle/setup_secrets.py (which reads os.environ for these keys).
# load_config_from_file then persists all vars from that file for the
# test runner, so no separate write_env calls are needed.
certs = ROOT / "test/certificates"
os.environ["CSFLE_TLS_CA_FILE"] = str(certs / "ca.pem")
os.environ["CSFLE_TLS_CERT_FILE"] = str(certs / "kms-server.pem")
os.environ["CSFLE_TLS_CLIENT_CERT_FILE"] = str(certs / "client.pem")
os.environ["CSFLE_TLS_WRONG_HOST_FILE"] = str(certs / "kms-wrong-host.pem")
os.environ["CSFLE_TLS_EXPIRED_FILE"] = str(certs / "kms-expired.pem")

run_command(f"bash {csfle_dir.as_posix()}/setup-secrets.sh", cwd=csfle_dir)
load_config_from_file(csfle_dir / "secrets-export.sh")
run_command(f"bash {csfle_dir.as_posix()}/start-servers.sh")
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/test-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,18 @@ jobs:
- id: setup-mongodb
uses: mongodb-labs/drivers-evergreen-tools@master
- name: Run tests
run: |
run: |
just integration-tests
- id: setup-mongodb-ssl
uses: mongodb-labs/drivers-evergreen-tools@master
with:
ssl: true
env:
# drivers-evergreen-tools invokes run-mongodb.sh directly (not via
# run_server.py), so cert paths must be provided explicitly here.
TLS_PEM_KEY_FILE: ${{ github.workspace }}/test/certificates/server.pem
TLS_CA_FILE: ${{ github.workspace }}/test/certificates/ca.pem
TLS_CERT_KEY_FILE: ${{ github.workspace }}/test/certificates/client.pem
- name: Run tests
run: |
just integration-tests
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ repos:
# - test/test_bson.py:267: isnt ==> isn't
# - test/versioned-api/crud-api-version-1-strict.json:514: nin ==> inn, min, bin, nine
# - test/test_client.py:188: te ==> the, be, we, to
args: ["-L", "fle,fo,infinit,isnt,nin,te,aks"]
args: ["-L", "fle,fo,infinit,isnt,nin,te,aks", "--skip", "test/certificates/*.pem"]

- repo: local
hooks:
Expand Down
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,16 @@ client = MongoClient(
If you want to use the actual certificate file then set `tlsCertificateKeyFile` to the local path
to `<repo_roo>/test/certificates/client.pem` and `tlsCAFile` to the local path to `<repo_roo>/test/certificates/ca.pem`.

#### Regenerating test certificates

If the test certificates in `test/certificates/` need to be regenerated (e.g. after expiry or to add missing extensions), run:

```bash
cd test/certificates && bash gen-certs.sh
```

See `test/certificates/README.md` for full details and constraints on certificate subjects/SANs that must be preserved.

### Encryption tests

- Run `just run-server` to start the server.
Expand Down
5 changes: 2 additions & 3 deletions test/asynchronous/test_encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -3039,10 +3039,9 @@ async def asyncSetUp(self):
async def http_post(self, path, data=None):
# Note, the connection to the mock server needs to be closed after
# each request because the server is single threaded.
ctx = ssl.create_default_context(cafile=CA_PEM)
ctx = ssl.create_default_context()
ctx.load_verify_locations(cafile=CA_PEM)
ctx.load_cert_chain(CLIENT_PEM)
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
conn = http.client.HTTPSConnection("127.0.0.1:9003", context=ctx)
try:
if data is not None:
Expand Down
88 changes: 88 additions & 0 deletions test/certificates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Test TLS Certificates

These certificates are used by the PyMongo test suite for TLS/SSL integration tests.

## Regenerating certificates

Run the generation script from this directory:

```bash
uv run gen-certs.py
```

**Prerequisites:** Python 3 and [uv](https://docs.astral.sh/uv/). The script declares its own dependency on `cryptography` via PEP 723 inline metadata, so `uv` installs it automatically.

## Certificate details

Two classes of leaf certificate are generated, with different extension profiles to satisfy
conflicting requirements from Python's ssl module and macOS's SecTrust framework:

**MongoDB certs** — presented to MongoDB Enterprise, verified by Apple SecTrust on macOS.
No Authority Key Identifier (AKI) or Subject Key Identifier (SKI). Adding AKI causes SecTrust to attempt OCSP revocation checks; because our
CA is not in the macOS system keychain, those checks fail with `CSSMERR_TP_CERT_SUSPENDED`.

**KMS certs** — presented by KMS mock servers, verified by Python's ssl module (OpenSSL).
Carry both AKI and SKI. Python 3.13 requires AKI on non-root certs; Python 3.14 enables
`X509_V_FLAG_X509_STRICT` in `ssl.create_default_context()`, which requires SKI too.

| File | Subject | Signed by | Extensions | Purpose |
|---|---|---|---|---|
| `ca.pem` | `CN=Drivers Testing CA, ...` | Self (CA) | basicConstraints critical, keyUsage critical, SKI | Root CA for all test certs |
| `server.pem` | `CN=localhost, ...` + SAN | Drivers Testing CA | SAN only | MongoDB server cert (key + cert) |
| `client.pem` | `CN=client, O=MDB, ...` | Drivers Testing CA | keyUsage, extKeyUsage | Client auth cert (key + cert) |
| `password_protected.pem` | Same as client | Drivers Testing CA | keyUsage, extKeyUsage | Client cert with AES-256 encrypted key |
| `crl.pem` | — | Drivers Testing CA | — | CRL revoking serial 1 (server.pem) |
| `kms-server.pem` | `CN=localhost, ...` + SAN | Drivers Testing CA | SAN, AKI, SKI | KMS mock server cert (key + cert) |
| `kms-wrong-host.pem` | `CN=wronghost.example.com` | Drivers Testing CA | SAN, AKI, SKI | KMS wrong-host test cert |
| `kms-expired.pem` | `CN=localhost, ...` + SAN | Drivers Testing CA | SAN, AKI, SKI | KMS expired cert (validity 2000–2001) |
| `trusted-ca.pem` | `CN=Trusted Kernel Test CA, ...` | Self (CA) | basicConstraints critical, keyUsage critical | Separate CA for CA-bundle tests |

**Password** for `password_protected.pem`: `qwerty`

## Important constraints

The following values are hardcoded in tests and **must not change**:

- Client cert subject: `C=US,ST=New York,L=New York City,O=MDB,OU=Drivers,CN=client`
(used as the MongoDB X.509 username in `test/test_ssl.py`)
- Server cert SAN: `DNS:localhost, IP:127.0.0.1, IP:::1`
- The `server` hostname alias for `127.0.0.1` must be present in `/etc/hosts` for SSL tests to pass
(added automatically by `.evergreen/scripts/setup-system.sh`)

## Background

Certificates were regenerated for PYTHON-5040 to fix `ssl.SSLCertVerificationError` failures on
macOS and Windows with Python 3.13+. The root causes were:

1. Python 3.13 enables `X509_V_FLAG_X509_STRICT` in `ssl.create_default_context()`, which
requires **AKI** on non-root certs. The KMS mock-server connection (`http_post`) used
`create_default_context()`, so the original 2019 KMS certs (no AKI) started failing.
2. Python 3.14 sets OpenSSL's `X509_V_FLAG_X509_STRICT` (via `ssl.VERIFY_X509_STRICT`) in
`ssl.create_default_context()`, which additionally requires **SKI** on non-root certs and
**keyUsage** on CA certs.

The MongoDB certs intentionally carry no AKI: Apple SecTrust triggers OCSP revocation checks when
any cert in the chain has AKI, and those checks fail with `CSSMERR_TP_CERT_SUSPENDED` because our
test CA is not in the macOS system keychain. The CA carries SKI (but not AKI); macOS SecTrust
OCSP is triggered by AKI on leaf certs, so the CA's SKI does not re-enable OCSP.

MongoDB Enterprise on macOS uses Apple SecTrust with `kSecRevocationRequirePositiveResponse`, which
requires a positive OCSP response for every cert in the chain regardless of whether AKI is present.
Because our test CA has no OCSP responder, the server startup always fails with
`CSSMERR_TP_CERT_SUSPENDED` without `--tls-allow-invalid-certificates`. This flag is set for
macOS in `.evergreen/scripts/run_server.py`.

As long as the driver verifies MongoDB server certs without `X509_V_FLAG_X509_STRICT` (which is
the case — `pymongo.ssl_support.get_ssl_context` uses `PROTOCOL_SSLv23`), no AKI is required on
the MongoDB leaf certs.

KMS connections use `ssl.create_default_context()`, which sets OpenSSL's `X509_V_FLAG_X509_STRICT`
via `ssl.VERIFY_X509_STRICT`. The CA cert carries SKI, enabling keyid-form AKI on the KMS leaf
certs. OpenSSL 3.3+ strict mode requires the `keyIdentifier` field within AKI (issuer/serial form
is not sufficient). macOS SecTrust OCSP is triggered by AKI on leaf certs that identify an issuer
— since the MongoDB leaf certs carry no AKI, adding SKI to the CA does not re-enable OCSP checks.

> **If the driver is changed to use `ssl.create_default_context()` for MongoDB connections**, the
> MongoDB certs will need AKI and SKI. Adding AKI will re-trigger macOS SecTrust OCSP failures;
> to resolve that, either add `--tls-allow-invalid-certificates` to the server startup in
> `run_server.py`, or install the test CA into the macOS system keychain in the CI setup.
39 changes: 20 additions & 19 deletions test/certificates/ca.pem
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
88 changes: 44 additions & 44 deletions test/certificates/client.pem
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAsNS8UEuin7/K29jXfIOLpIoh1jEyWVqxiie2Onx7uJJKcoKo
khA3XeUnVN0k6X5MwYWcN52xcns7LYtyt06nRpTG2/emoV44w9uKTuHsvUbiOwSV
m/ToKQQ4FUFZoqorXH+ZmJuIpJNfoW+3CkE1vEDCIecIq6BNg5ySsPtvSuSJHGjp
mc7/5ZUDvFE2aJ8QbJU3Ws0HXiEb6ymi048LlzEL2VKX3w6mqqh+7dcZGAy7qYk2
5FZ9ktKvCeQau7mTyU1hsPrKFiKtMN8Q2ZAItX13asw5/IeSTq2LgLFHlbj5Kpq4
GmLdNCshzH5X7Ew3IYM8EHmsX8dmD6mhv7vpVwIDAQABAoIBABOdpb4qhcG+3twA
c/cGCKmaASLnljQ/UU6IFTjrsjXJVKTbRaPeVKX/05sgZQXZ0t3s2mV5AsQ2U1w8
Cd+3w+qaemzQThW8hAOGCROzEDX29QWi/o2sX0ydgTMqaq0Wv3SlWv6I0mGfT45y
/BURIsrdTCvCmz2erLqa1dL4MWJXRFjT9UTs5twlecIOM2IHKoGGagFhymRK4kDe
wTRC9fpfoAgyfus3pCO/wi/F8yKGPDEwY+zgkhrJQ+kSeki7oKdGD1H540vB8gRt
EIqssE0Y6rEYf97WssQlxJgvoJBDSftOijS6mwvoasDUwfFqyyPiirawXWWhHXkc
DjIi/XECgYEA5xfjilw9YyM2UGQNESbNNunPcj7gDZbN347xJwmYmi9AUdPLt9xN
3XaMqqR22k1DUOxC/5hH0uiXir7mDfqmC+XS/ic/VOsa3CDWejkEnyGLiwSHY502
wD/xWgHwUiGVAG9HY64vnDGm6L3KGXA2oqxanL4V0+0+Ht49pZ16i8sCgYEAw+Ox
CHGtpkzjCP/z8xr+1VTSdpc/4CP2HONnYopcn48KfQnf7Nale69/1kZpypJlvQSG
eeA3jMGigNJEkb8/kaVoRLCisXcwLc0XIfCTeiK6FS0Ka30D/84Qm8UsHxRdpGkM
kYITAa2r64tgRL8as4/ukeXBKE+oOhX43LeEfyUCgYBkf7IX2Ndlhsm3GlvIarxy
NipeP9PGdR/hKlPbq0OvQf9R1q7QrcE7H7Q6/b0mYNV2mtjkOQB7S2WkFDMOP0P5
BqDEoKLdNkV/F9TOYH+PCNKbyYNrodJOt0Ap6Y/u1+Xpw3sjcXwJDFrO+sKqX2+T
PStG4S+y84jBedsLbDoAEwKBgQCTz7/KC11o2yOFqv09N+WKvBKDgeWlD/2qFr3w
UU9K5viXGVhqshz0k5z25vL09Drowf1nAZVpFMO2SPOMtq8VC6b+Dfr1xmYIaXVH
Gu1tf77CM9Zk/VSDNc66e7GrUgbHBK2DLo+A+Ld9aRIfTcSsMbNnS+LQtCrQibvb
cG7+MQKBgQCY11oMT2dUekoZEyW4no7W5D74lR8ztMjp/fWWTDo/AZGPBY6cZoZF
IICrzYtDT/5BzB0Jh1f4O9ZQkm5+OvlFbmoZoSbMzHL3oJCBOY5K0/kdGXL46WWh
IRJSYakNU6VIS7SjDpKgm9D8befQqZeoSggSjIIULIiAtYgS80vmGA==
MIIEpAIBAAKCAQEAv27OLCiZ7xI5cUs1Kmj+QQWcKywpZX0dLtVvGj3OLtd7UbT3
fIWpnLsmSXOk+/NRBFdPLgGUnq8QBUuJrB3+TD8lb15oPyEuUfdtyHQbsBkEdNbz
HS2djy33BYgColt8EN/rGtODMMtBn6Vlb9zLuJi4F5iXzS4AckdBzxi/tFrOP97N
vKxVFGebJvMhw6QRWr8SR9aEx8cc4TQCCKly2Mv2WUVLeX6LsB9ucvZhMrN1BZ9f
LiBBTCTXzNQYGW2scpecDfa0Cz3eJnAliZrWhDTEZCD2MzDhozR+JlpyfJbcaBde
kSNMZy0CGpUVD3aGAhHYrKrJMbZWXxz5t6+QGQIDAQABAoIBABlS8Yfv8GUq9lm2
xu1kVEuKZXK59dlM0svQ76X7X8eHOUjBdYKN4AvcH3V/YeeentdsgWH8Ut/RwtR1
01w8ii57UAV1P2R9NuEgUpqTmYdogn6+YgzjGEEfpdpKeCa9js0LV3uwrV3gFZSm
pE5HBCrYW8oV+pw++094KQwvdvTHBPA694mZz+waXaFOvMo0nQyQ5+RN3HSYH0ID
dDfeLbHMUUCLGaOtNtQZmAiYv+rxRXNY0AgOATyciiKV9AIt6FXHbm4h7rUmDfh/
OqU6jmKRbC6aBy/m8HmLdph5Veviy9K0lzJJwOD8XzhtvQwupotzOMMF3cygHv40
zYMzxl0CgYEA80fBl6E7hh2J+3L77VZOqq5nFhnS2rASTmdksSbpwUku/TnMOqof
K0Bt+//gCO05UUCeHAhg6xS9Sg9Wm14SQQVmubNVkRStP2OFcaPmg/31iGbw9XIg
KlhbeIwvFtuC2kRsxUHTznQfZqvUPcfsdOrmqlSC5WlH/oJSSTCnlf8CgYEAyXEV
kgWMxqPN2pJ/0bnHt5DBfF2P5CvJwZt7BAy4ab05X3ZLk7IVumtUhxCCPFO70ZB5
7FadllVkYcdepGdwuU0/kDqrTxDrxTNiTDhPALApwUdduAm7BhRAeY+88zNyuU7Q
i6lX9i+v2VHivrbcH7vJIZS4KQCWFG4TpHhOyecCgYEAnjiZ6MLc0qHdfqLOxBHw
wcMBmncbEk2W6lUGQMzdFG9DVz/C2piQAvI5Vb6Zd1TJhVWwPu0YE2v+m+8T1aI9
3vnjUH0Y9m1rK6HPRRRitI9zo83HgupBjyi9/M23RndnSAteboAcf9Y4Ie847yFa
YMPxVu/13bw2LYmWeLFjHQMCgYEAjpL0UmqNLdaoD0hbIWRdX6Yb29sYycTYQqi6
E66xI13japZ+fWWxDUWECSh9FRequnOIZ+cSGGIN70q9yJzR4sUy9PEhaI+wX92z
eADuoa0NkJfjVCvG7FGPJLrAYF2MmG2ZGxBbiopL6wOS+arQ98DgZV0uTw70KjeS
vXjNQwcCgYBjRd2jXGA3STGVCSM64RcZKM3wEeiFzqMZP6H3LZ9KurEtYDltfmrY
MhlH7cCw8uppIYJlRwWIGeVv0iUx44PBNb/l1idTrqf6SSzEnb4H4zJjXKBaVFfu
JVsBcdq5EinSKCAHnBSVKOb5xpRGYili8ch/QRIvVECjchaMgbDR3Q==
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDgzCCAmugAwIBAgIDAxOUMA0GCSqGSIb3DQEBCwUAMHkxGzAZBgNVBAMTEkRy
aXZlcnMgVGVzdGluZyBDQTEQMA4GA1UECxMHRHJpdmVyczEQMA4GA1UEChMHTW9u
Z29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsx
CzAJBgNVBAYTAlVTMB4XDTE5MDUyMjIzNTU1NFoXDTM5MDUyMjIzNTU1NFowaTEP
MA0GA1UEAxMGY2xpZW50MRAwDgYDVQQLEwdEcml2ZXJzMQwwCgYDVQQKEwNNREIx
FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALDUvFBLop+/
ytvY13yDi6SKIdYxMllasYontjp8e7iSSnKCqJIQN13lJ1TdJOl+TMGFnDedsXJ7
Oy2LcrdOp0aUxtv3pqFeOMPbik7h7L1G4jsElZv06CkEOBVBWaKqK1x/mZibiKST
X6FvtwpBNbxAwiHnCKugTYOckrD7b0rkiRxo6ZnO/+WVA7xRNmifEGyVN1rNB14h
G+spotOPC5cxC9lSl98Opqqofu3XGRgMu6mJNuRWfZLSrwnkGru5k8lNYbD6yhYi
rTDfENmQCLV9d2rMOfyHkk6ti4CxR5W4+SqauBpi3TQrIcx+V+xMNyGDPBB5rF/H
Zg+pob+76VcCAwEAAaMkMCIwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF
BwMCMA0GCSqGSIb3DQEBCwUAA4IBAQAqRcLAGvYMaGYOV4HJTzNotT2qE0I9THNQ
wOV1fBg69x6SrUQTQLjJEptpOA288Wue6Jt3H+p5qAGV5GbXjzN/yjCoItggSKxG
Xg7279nz6/C5faoIKRjpS9R+MsJGlttP9nUzdSxrHvvqm62OuSVFjjETxD39DupE
YPFQoHOxdFTtBQlc/zIKxVdd20rs1xJeeU2/L7jtRBSPuR/Sk8zot7G2/dQHX49y
kHrq8qz12kj1T6XDXf8KZawFywXaz0/Ur+fUYKmkVk1T0JZaNtF4sKqDeNE4zcns
p3xLVDSl1Q5Gwj7bgph9o4Hxs9izPwiqjmNaSjPimGYZ399zcurY
MIIDgTCCAmmgAwIBAgIBAjANBgkqhkiG9w0BAQsFADB5MRswGQYDVQQDDBJEcml2
ZXJzIFRlc3RpbmcgQ0ExEDAOBgNVBAsMB0RyaXZlcnMxEDAOBgNVBAoMB01vbmdv
REIxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxETAPBgNVBAgMCE5ldyBZb3JrMQsw
CQYDVQQGEwJVUzAeFw0yNjA2MTQxNTExNTlaFw00NjA2MTAxNTExNTlaMGkxDzAN
BgNVBAMMBmNsaWVudDEQMA4GA1UECwwHRHJpdmVyczEMMAoGA1UECgwDTURCMRYw
FAYDVQQHDA1OZXcgWW9yayBDaXR5MREwDwYDVQQIDAhOZXcgWW9yazELMAkGA1UE
BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/bs4sKJnvEjlx
SzUqaP5BBZwrLCllfR0u1W8aPc4u13tRtPd8hamcuyZJc6T781EEV08uAZSerxAF
S4msHf5MPyVvXmg/IS5R923IdBuwGQR01vMdLZ2PLfcFiAKiW3wQ3+sa04Mwy0Gf
pWVv3Mu4mLgXmJfNLgByR0HPGL+0Ws4/3s28rFUUZ5sm8yHDpBFavxJH1oTHxxzh
NAIIqXLYy/ZZRUt5fouwH25y9mEys3UFn18uIEFMJNfM1BgZbaxyl5wN9rQLPd4m
cCWJmtaENMRkIPYzMOGjNH4mWnJ8ltxoF16RI0xnLQIalRUPdoYCEdisqskxtlZf
HPm3r5AZAgMBAAGjJDAiMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
AjANBgkqhkiG9w0BAQsFAAOCAQEALhvRiiV/C5uAt7xmyMalHuQqBhR67gA55jBb
faIKSnhEBcWaOAx+2PiHMRhI4BraOxDT2IIjar1vL/Lp4QB81RIfBTjefVgldGOD
FjvyU2PrBLoeVLOsrtYdjyjwciXrErYRKyOx9B+cBm5hUKA2kTnJz8ad+01Qquw5
s+e8rzVRL4Brrc3L2F0MURrx6H3VPwXSbVk8hFc4qSBf1WHSULkjVD/QP0uitwH4
qKCRhq/h9m43IPRE+rLseldJhAWvlqMNxyJLoSOLgOfUd0iXV8pGqN+OOx4OJGPS
g4ry+fZLqf+k6Du7pfrdlv3VOwC4tylSsl0EyzlLqDtXO20G9A==
-----END CERTIFICATE-----
Loading
Loading