Skip to content

Commit 77b1113

Browse files
committed
FEATURE-ci-tls-ca-fixture: Repair strict TLS fixture certificate chains
Reissue the static server chain with valid CA key usage while retaining leaf keys and exact certificate identities, dates and serials. Add missing rotation CA and issuer identifiers without changing malformed ACME or mTLS fixtures. Keep server-fixture regeneration in the independent tooling and register real strict handshake regressions in the TLS-on lane. Verified seven focused tests through the configured Make target, original/repaired OpenSSL 3.5.9 strict chain counterfactuals, preserved ACME extension semantics, bootstrap/configure, changed C++ cpplint, Python syntax and diff checks. Native macOS/Python 3.14 remains CI/v3-PR owned; task stays In Progress pending caller validation and finalization.
1 parent f3e01f9 commit 77b1113

9 files changed

Lines changed: 333 additions & 48 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,5 @@ __pycache__/
177177
!scripts/test-v3-platform-ci.py
178178
!test/integ/release_ci_test.py
179179
!test/integ/release_platform_bundle_test.py
180+
181+
!scripts/test-v3-tls-fixtures.py

‎Makefile.am‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ check-hygiene:
286286
# still runs the full test suite plus the header / example / lint gates, but
287287
# skips the source-only doc gates whose inputs it cannot satisfy. Release runners
288288
# may provide a verified specs/ tooling bundle; it is not a source checkout.
289-
check-local: check-v3-compiled-operations check-headers check-examples lint-warning-suppressions lint-littletest-skip-exit-code lint-fence-balance check-v3-native-linkage check-v3-stage-install
289+
check-local: check-v3-compiled-operations check-headers check-examples lint-warning-suppressions lint-littletest-skip-exit-code lint-fence-balance check-v3-native-linkage check-v3-stage-install $(V3_TLS_FIXTURE_CHECK)
290290
@if test -d "$(top_srcdir)/specs" && test -e "$(top_srcdir)/.git"; then \
291291
$(MAKE) $(AM_MAKEFLAGS) check-readme check-release-notes check-doxygen ; \
292292
else \
@@ -643,3 +643,15 @@ EXTRA_DIST += .github/workflows/codeql-analysis.yml .github/workflows/verify-bui
643643
EXTRA_DIST += docs/v3-ci.md
644644

645645
EXTRA_DIST += scripts/ci-macos-toolchain.sh scripts/test-v3-platform-ci.py
646+
647+
# Real independent certificate fixtures must satisfy strict client verification.
648+
EXTRA_DIST += scripts/test-v3-tls-fixtures.py
649+
if NATIVE_V3_TLS
650+
V3_TLS_FIXTURE_CHECK = check-v3-tls-fixtures
651+
check-v3-tls-fixtures:
652+
@CXX="$(CXX)" V3_TLS_CFLAGS="$(V3_TLS_CFLAGS)" V3_TLS_LIBS="$(V3_TLS_LIBS)" python3 $(top_srcdir)/scripts/test-v3-tls-fixtures.py
653+
else
654+
check-v3-tls-fixtures:
655+
@echo "check-v3-tls-fixtures: requires the TLS-on provider lane"
656+
endif
657+
.PHONY: check-v3-tls-fixtures

‎scripts/test-v3-tls-fixtures.py‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env python3
2+
"""Real independent fixture generation and strict TLS handshakes; no server library."""
3+
import os
4+
from pathlib import Path
5+
import shlex
6+
import shutil
7+
import ssl
8+
import subprocess
9+
import tempfile
10+
import unittest
11+
12+
SOURCE = Path(__file__).resolve().parent.parent
13+
14+
15+
class TLSFixtures(unittest.TestCase):
16+
@classmethod
17+
def setUpClass(cls):
18+
cls.temporary = tempfile.TemporaryDirectory(prefix='v3-tls-fixtures-')
19+
cls.addClassCleanup(cls.temporary.cleanup)
20+
cls.root = Path(cls.temporary.name).resolve()
21+
cls.fixtures = cls.root / 'fixtures'
22+
shutil.copytree(SOURCE / 'test/data/tls_credentials', cls.fixtures)
23+
executable = cls.root / ('client.exe' if os.name == 'nt' else 'client')
24+
cls.executable = executable
25+
command = (shlex.split(os.environ.get('CXX', 'c++')) + ['-std=c++20']
26+
+ shlex.split(os.environ.get('V3_TLS_CFLAGS', ''))
27+
+ [str(SOURCE / 'test/installed/tls_client.cpp')]
28+
+ shlex.split(os.environ.get('V3_TLS_LIBS', '-lssl -lcrypto'))
29+
+ (['-lws2_32'] if os.name == 'nt' else []) + ['-o', str(executable)])
30+
subprocess.run(command, check=True, capture_output=True, text=True, timeout=60)
31+
subprocess.run([str(executable), 'fixtures', str(cls.fixtures)], check=True,
32+
capture_output=True, text=True, timeout=10)
33+
34+
def handshake(self, identity, host='a.example', trust='root', client=None):
35+
"""Exchange real TLS records in memory, including certificate/hostname verification."""
36+
chain = self.root / (identity + '-chain.pem')
37+
chain.write_bytes((self.fixtures / (identity + '.pem')).read_bytes()
38+
+ ((self.fixtures / 'intermediate.pem').read_bytes()
39+
if identity in ('a', 'b') else b''))
40+
server = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
41+
server.load_cert_chain(str(chain), str(self.fixtures / (identity + '-key.pem')))
42+
if client:
43+
server.load_verify_locations(str(self.fixtures / 'client-root.pem'))
44+
server.verify_mode = ssl.CERT_REQUIRED
45+
context = ssl.create_default_context(cafile=str(self.fixtures / (trust + '.pem')))
46+
# Python 3.14 enables this by default; exercise the same policy on older Python.
47+
context.verify_flags |= ssl.VERIFY_X509_STRICT
48+
self.assertTrue(context.check_hostname)
49+
self.assertEqual(ssl.CERT_REQUIRED, context.verify_mode)
50+
if client:
51+
client_chain = self.root / (client + '-chain.pem')
52+
client_chain.write_bytes((self.fixtures / (client + '.pem')).read_bytes()
53+
+ ((self.fixtures / 'client-intermediate.pem').read_bytes()
54+
if client != 'client-other' else b''))
55+
context.load_cert_chain(str(client_chain), str(self.fixtures / (client + '-key.pem')))
56+
inbound, outbound = [ssl.MemoryBIO(), ssl.MemoryBIO()], [ssl.MemoryBIO(), ssl.MemoryBIO()]
57+
peers = [context.wrap_bio(inbound[0], outbound[0], server_hostname=host),
58+
server.wrap_bio(inbound[1], outbound[1], server_side=True)]
59+
done = [False, False]
60+
for _ in range(20):
61+
for index, peer in enumerate(peers):
62+
if not done[index]:
63+
try:
64+
peer.do_handshake()
65+
done[index] = True
66+
except ssl.SSLWantReadError:
67+
pass
68+
inbound[1 - index].write(outbound[index].read())
69+
if all(done):
70+
peers[0].write(b'fixture-ok')
71+
inbound[1].write(outbound[0].read())
72+
self.assertEqual(b'fixture-ok', peers[1].read())
73+
return
74+
self.fail('TLS handshake did not complete within 20 record exchanges')
75+
76+
def test_static_sni_chains_pass_strict_handshake(self):
77+
for name in ('a', 'b'):
78+
with self.subTest(identity=name):
79+
self.handshake(name, name + '.example')
80+
81+
def test_rotation_chain_passes_strict_handshake(self):
82+
self.handshake('a-replacement')
83+
84+
def test_wrong_hostname_is_rejected(self):
85+
for name in ('a', 'b', 'a-replacement'):
86+
with self.subTest(identity=name):
87+
with self.assertRaises(ssl.SSLCertVerificationError) as error:
88+
self.handshake(name, 'wrong.example')
89+
self.assertEqual(62, error.exception.verify_code, str(error.exception))
90+
91+
def test_untrusted_chain_is_rejected(self):
92+
for name in ('a', 'b', 'a-replacement'):
93+
with self.subTest(identity=name):
94+
with self.assertRaises(ssl.SSLCertVerificationError) as error:
95+
self.handshake(name, name + '.example' if name == 'b' else 'a.example', 'client-root')
96+
self.assertIn(error.exception.verify_code, (20, 21), str(error.exception))
97+
98+
def test_server_fixture_regeneration_preserves_leaf_material(self):
99+
regenerated = self.root / 'regenerated'
100+
shutil.copytree(SOURCE / 'test/data/tls_credentials', regenerated)
101+
result = subprocess.run([str(self.executable), 'regenerate-server', str(regenerated)],
102+
capture_output=True, text=True, timeout=10)
103+
self.assertEqual(0, result.returncode, result.stdout + result.stderr)
104+
for path in (SOURCE / 'test/data/tls_credentials').iterdir():
105+
if path.name not in ('root.pem', 'intermediate.pem', 'a.pem', 'b.pem'):
106+
self.assertEqual(path.read_bytes(), (regenerated / path.name).read_bytes(), path.name)
107+
for name in ('root', 'intermediate', 'a', 'b'):
108+
flags = ['-noout', '-dates', '-serial', '-subject', '-issuer']
109+
if name in ('a', 'b'):
110+
flags.append('-pubkey')
111+
def metadata(directory):
112+
return subprocess.run([os.environ.get('OPENSSL', 'openssl'), 'x509',
113+
'-in', str(directory / (name + '.pem'))] + flags,
114+
check=True, capture_output=True, timeout=5).stdout
115+
self.assertEqual(metadata(SOURCE / 'test/data/tls_credentials'), metadata(regenerated))
116+
self.fixtures = regenerated
117+
self.handshake('a')
118+
self.handshake('b', 'b.example')
119+
120+
def test_valid_mtls_client_is_accepted(self):
121+
self.handshake('a', client='client-valid')
122+
123+
def test_negative_mtls_clients_are_rejected(self):
124+
for client in ('client-other', 'client-expired', 'client-wrong-purpose'):
125+
with self.subTest(client=client):
126+
with self.assertRaises(ssl.SSLCertVerificationError) as error:
127+
self.handshake('a', client=client)
128+
self.assertEqual({'client-other': 20, 'client-expired': 10,
129+
'client-wrong-purpose': 26}[client], error.exception.verify_code)
130+
131+
132+
if __name__ == '__main__':
133+
unittest.main()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# FEATURE-ci-tls-ca-fixture: make independent TLS fixture chains strictly valid
2+
3+
Status: In Progress — implementation complete; caller validation/finalization pending.
4+
Base: local `v3` at `f3e01f9dddc07c5aa94051b89220095d05c47f53`.
5+
Evidence: `.debug/ci-tls-ca-fixture-a1jpmct9/journal.md` and its `implementation/` logs.
6+
7+
The macOS checkout package job `120468733495` (run `39969683050`) fails
8+
`check-v3-public-tls.py` at its initial SNI loop, line 117, with certificate
9+
verification error 92: CA certificate lacks key usage. Those initial connections
10+
serve the copied static a/b certificates, through intermediate.pem and root.pem.
11+
Real strict verification reproduces missing key usage on both static CAs.
12+
The generated rotation chain has a separate instance of incomplete extensions:
13+
strict verification reports missing leaf authority key identifier (85), root
14+
key usage (92), and root subject key identifier (86). A rotation-only repair
15+
would leave the observed CI failure intact.
16+
17+
Action items:
18+
19+
- [x] Read the plan correction, literal journal and actual macOS traceback; isolate
20+
this worktree from the exact local v3 base and preserve other work.
21+
- [x] Observe RED with the real independent C++ fixture generator, copied static
22+
credentials, and real strict TLS handshakes, including error 92 on a/b and
23+
error 85 on rotation. Repeat the causal original/repaired comparison with
24+
the existing supported OpenSSL 3.5.9 verifier.
25+
- [x] Add critical certificate-signing/CRL-signing key usage to both static CAs;
26+
reissue their chain while preserving existing a/b leaf private/public keys,
27+
all subjects/issuer names, exact validity dates and serial numbers.
28+
- [x] Add rotation root key usage/SKI and leaf AKI before signing, without changing
29+
the intentionally malformed ACME generator variants or client verification policy.
30+
- [x] Retain reproducible server-fixture regeneration in the existing independent
31+
tool; preserve all mTLS credentials and private-key files byte-for-byte.
32+
- [x] Verify actual strict handshakes, hostname/untrusted-chain rejection, valid
33+
mTLS acceptance and rejection for expired, untrusted and wrong-purpose clients.
34+
- [x] Register/distribute the focused test in TLS-on check-local; run the configured
35+
standalone Make target, bootstrap, changed-file cpplint, syntax and diff checks.
36+
- [ ] Caller: Groundwork validation and finalization into v3.
37+
- [ ] CI / v3 PR: native macOS/Python 3.14 checkout/archive public TLS matrices.
38+
39+
Implementation and reproduction:
40+
41+
`test/installed/tls_client.cpp` already generates the installed-consumer rotation
42+
and ACME fixtures independently of libhttpserver. Its `regenerate-server DIR`
43+
mode now regenerates only root.pem, intermediate.pem, a.pem and b.pem using the
44+
existing certificates as templates. For example, after compiling that tool
45+
against the selected provider, run `independent-client regenerate-server
46+
COPIED_FIXTURE_DIRECTORY`. Its existing `fixtures DIR` mode remains separate.
47+
Original CA private keys were never tracked; changing signed CA extensions
48+
requires replacement test CA keypairs and re-signing the server chain. New
49+
RSA-2048 CA keys are ephemeral and discarded. Regeneration reproduces the
50+
chain/metadata invariant with fresh random CA keys, rather than byte-identical
51+
certificates. All leaf keys, exact dates/serials and negative client credentials
52+
remain unchanged. Only CA public keys, related key identifiers and signatures
53+
change in the four static certificates, in addition to the new CA key usages.
54+
55+
OpenSSL's [strict verification documentation](https://docs.openssl.org/3.5/man1/openssl-verification-options/)
56+
requires key usage for CAs, SKI for version 3 CAs, and AKI for non-self-signed
57+
version 3 certificates. The repair satisfies those chain checks without changing
58+
runtime code, security policy, provider selection, dependencies or CI pins.
59+
60+
Local verification and limits:
61+
62+
- Seven focused tests pass through `make check-v3-tls-fixtures` in a real
63+
TLS-on configured build using existing OpenSSL 3.5.9 headers/static libraries.
64+
The test compiles/runs the actual independent C++ fixture tool, exchanges real
65+
TLS records through Python SSL MemoryBIOs, and sends application data after
66+
successful handshakes. Python 3.12.3 uses system OpenSSL 3.0.13 with
67+
`VERIFY_X509_STRICT` enabled explicitly to match the newer Python client policy.
68+
- The supported OpenSSL 3.5.9 executable separately verifies original a/b chains
69+
fail with error 92 and original rotation fails with 85/92/86. Repaired a/b and
70+
rotation pass `verify -x509_strict -purpose sslserver -verify_hostname ...`.
71+
This executable links the existing provider statically; changing LD_LIBRARY_PATH
72+
does not replace Python's separate system OpenSSL engine.
73+
- Wrong host fails specifically with verification code 62; untrusted server
74+
chains fail with 20/21. mTLS negatives fail specifically with 20 (untrusted),
75+
10 (expired), and 26 (wrong purpose); the valid client completes a handshake.
76+
- Original/repaired actual generator outputs retain identical extension content
77+
for all twelve ACME variants. The ACME generator loop is unchanged, including
78+
expired/future date logic. No malformed-certificate acceptance is claimed.
79+
- A regeneration test checks certificate dates/serials/subjects/issuer names,
80+
unchanged leaf public keys, every untouched file byte-for-byte, and strict a/b
81+
handshakes from a fresh regeneration. A retained pre-change hash/metadata
82+
manifest also confirms original leaf keys and mTLS fixture bytes were preserved.
83+
- `./bootstrap`, real TLS-on configure, configured focused Make target,
84+
`cpplint test/installed/tls_client.cpp`, Python AST syntax and `git diff --check`
85+
pass. Bootstrap retains existing aminclude.am .PHONY / AC_OUTPUT warnings;
86+
the C++ compiler retains the existing fclose-deleter attribute warning in the
87+
pre-existing fixture function. No new build warning was introduced.
88+
- No broad baseline, full public TLS matrix or nonlocal platform run was started.
89+
Native macOS/Python 3.14 execution remains CI / v3-PR owned, not passed locally.
90+
Prior Darwin deadline, old Linux parity and concurrent Windows install
91+
uncertainties remain closed to further diagnosis under this task.

‎test/data/tls_credentials/a.pem‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ bUIxXkyyzbdO0Pn93KgnhS6Tpjb5VSpFNQ1+KnafYUmKFjCvVT3fc2PY6aejHfnJ
99
dIHpe3ElECpbeuPwhDjx5hDTgQxXduNOkOawWAJ6nFRTN3EBdP59hLdOBHiH3ppx
1010
zm+hwRRj9xg7Tuq10/9jWimoWNrQxi8CAwEAAaNmMGQwDAYDVR0TAQH/BAIwADAU
1111
BgNVHREEDTALgglhLmV4YW1wbGUwHQYDVR0OBBYEFKg1sciHv3NIB1tfkf/7jvSD
12-
dIAFMB8GA1UdIwQYMBaAFE0G6u9Yw3UtnBzPEldmxzXksmADMA0GCSqGSIb3DQEB
13-
CwUAA4IBAQAiEOqnKdliz2YcUOYMcm9XsnnohsUOZRKlIsvO/KZxfo0tSNImhP4l
14-
bIJG2MccbJsAuQwvphYMI79ilBfN59w+XIUk1KinPu7yvlnsUeWqT67Iln0AjOi1
15-
qU9A+oE5hLN9yHDs+IhRBW0Zg9RB5lgnRg8ozc6mOKVGVbb86w+6yTGlrRk5Q3cm
16-
QdVlaDq2s3T1FtN+KZs17L8wFN9up516umGrlYKEoaNJtLC7JfoAhmUq2Bkn/gbG
17-
HlpV09U0ov03Y+CJhqSCjSUmlWv91Lu4I0M4jUfUXLCeJFW7ZHeVrfDoOhWXE/Ga
18-
YvmRFgHUPB8oAuSQJe5ewD2PZtprHdIq
12+
dIAFMB8GA1UdIwQYMBaAFPf1/w0eMonXp2q/iEQdf7WVs0M9MA0GCSqGSIb3DQEB
13+
CwUAA4IBAQB9pUEnG+LCia4ZOWgQHxG4NvuTMSbaIzgwLUkrVsUTk4ivH4V2bacf
14+
o5+KTN8sZhKL8PHzDisZF5HSqq8mZ4j9tMiMAKI3Sg6jVNZ4/G4CQIXvPPkcpTdW
15+
2Q/b6dHt4dD5i0zslGMIRI6EwNpyvnWgNBrRnMkbD6Hs+qr94qp9rUa7uPk6oZaW
16+
yo95k5PLiERVPuTTywq5rPjq0RISKHLfS4NIIbecE2ssrSLLiLlGighCWUngGcQv
17+
ZsaO2akhopIi8dG7d50FssrgBDP9Bku/kHgeBJfzIH3Pp7rOAAe+n75y4zVxZuBl
18+
S2WmcaBebP6q+E1kdFx/A0uDmBi15pTl
1919
-----END CERTIFICATE-----

‎test/data/tls_credentials/b.pem‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ w0frIAxv+WbXGu/e1s0JeqTljX/m79EBCXgkYiMM3eVJ6y86rQbREhM0gHNIrUwh
99
CtLYfMU4zOPPZMVf9H3rOccS39+mNxqmJDYNPf0hDeXHOalnHbVaK6dfwRS0LXA5
1010
5zLaX0mB6XuMgo+1/Jxhke88flK0geEbAgMBAAGjZjBkMAwGA1UdEwEB/wQCMAAw
1111
FAYDVR0RBA0wC4IJYi5leGFtcGxlMB0GA1UdDgQWBBScLyV/fQ3KcecQZwYUBOCN
12-
PjAWAjAfBgNVHSMEGDAWgBRNBurvWMN1LZwczxJXZsc15LJgAzANBgkqhkiG9w0B
13-
AQsFAAOCAQEAHinMtyou4s4ZFM+hcaZhOms1M8t2/a1ov0QgkKJ2m2l6IKOtcs1d
14-
0hGACH6cPW2tbcuTznHY1lr0/FcIZgnVDbx3IiEHCN0bxIdezeVBUIUHMrqtJ/dD
15-
+IZbimbjqQOSFyvezwJovHtuXVVbtZA02XZApgGGafevN8GLv4dIPmDH+262AHcj
16-
GSD1z39ZgsLBhp09PaZzxMqofzstn1iLIpfn5zyBTCGV2u5zLqrkcdxKuTVnnk7+
17-
duXYSiOqj98RL/zsQYr/vGZ2cCnrve6pu4XEXZJb06zQj7W+TynkSRMiGNQ419Px
18-
UNANmi8PoJHPd8S+sIHqhNZ19wkiQ9XNRQ==
12+
PjAWAjAfBgNVHSMEGDAWgBT39f8NHjKJ16dqv4hEHX+1lbNDPTANBgkqhkiG9w0B
13+
AQsFAAOCAQEANe/8gnVYlb19gl62iVsYlweCdvE38XMCaYxEjl+zC7oUbQDzykKR
14+
VVZpSfwEISoR7ZGyhDn57K/w3GTPF+xVL9yFeXwXFgEDD+9e4V8IaODkqLQ0BZYH
15+
+rHJeG+Xmea4Q+X7XFTG11HsKvHYW/tP3bNAq0Rl+bmwFlNqzTDgjd2zI71+TkRk
16+
G3t3Fyo9Tc+ef+eJEs0CrZw2mU4lUIKpfh0/ad/rrjClWOuWG8j1Z4ADfzEJsXCt
17+
+ky3oNQN7pETwT1Ln7OSPXPZjHAITqTCNW2Bdv1Wedv4Hgwxg0g3ew3M4TzbRN1L
18+
lugJPKpq2OmXOFozVXoY4vlIrog3owq8Qw==
1919
-----END CERTIFICATE-----
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
-----BEGIN CERTIFICATE-----
2-
MIIDBDCCAeygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxyb290
2+
MIIDFDCCAfygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxyb290
33
LmV4YW1wbGUwHhcNMjYxMDA3MDUxMDA4WhcNMzYxMDA0MDUxMDA4WjAfMR0wGwYD
44
VQQDDBRpbnRlcm1lZGlhdGUuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
5-
ADCCAQoCggEBAKZZmt25QAcWUGBVRmBc9SkDlRz//ZrbO30pGvTDkumhPwE5PJHn
6-
15x4e8k0VPRsgSs00XRv8nlLmv+ydBACtL8rMkPCKvKIuU0VZZ3qwbqZU8emLBME
7-
6x7Qb0U8Ce9vGxTaNJbmfze5Jq1RgOLusoyNp+Fp4lVIOiQqXvbxTGQA5WkY5U9Y
8-
S3sbMUj4xFxxtTHL6DgJw+gf1q+ldXapcF0kTDVyyhELD//l1C9nRrAOHxgx4ro6
9-
oV3A+CxxTaPppi+315it573WFDKiCd//zbF6WXwMRyiVhSOx9s1LhW5wnTkEObGn
10-
UjiQDxhrC4k3rTdme2nIptMuypdyvRSZRjkCAwEAAaNTMFEwDwYDVR0TAQH/BAUw
11-
AwEB/zAdBgNVHQ4EFgQUTQbq71jDdS2cHM8SV2bHNeSyYAMwHwYDVR0jBBgwFoAU
12-
n4aDyofdEPe7qMb1Eg7QfGoVYCAwDQYJKoZIhvcNAQELBQADggEBAENTYRi/EHo3
13-
s6A1p1C5R7fU4WvsKWry/GqTiQMLl/ulOUN3A4KWKMjNIjOz/pZjkPTEaMs0Pzsz
14-
mKawArvV9G9V4q7Tlevsea0iZ+/ks0DDWr9NS8q5CAvg13L3MFxo4YcaCM0wXhDN
15-
SN1r4MFYsRcFdSH5xPVTNlhuGOqoB7RLRPyLu1EyRS2rhETldDWFVxCLMLpZuNpV
16-
Ml+w4NHgGBZvTti+1eS+ZPwgZjUU/PIbDP1a81fahE0epy3A++/RUSX9+KItXko9
17-
O/nN667BxetBv5Rjb6Hn3dukw8VHVCbGb/V239N29yqNp4GMEOatXv9aCBZTVdPV
18-
9NcjUMRLzms=
5+
ADCCAQoCggEBAKddRzliAfAlEdLrXGwoDHbp5n4P8bHkb6quhVCAo35nwQ8tkxTv
6+
k1HXGyHEELbY9jly/LAcBfiL+CipbgBtytysIjaBLgVIxaQr4LBRwJ32FZ+K1fHu
7+
bJ5KOtXsRxoMcYLxkniRYwVB/qFBp3iLJyXHNnKbwOgYnNpSsjGvIqgdC0pKocLv
8+
60YIiW1VQwsgKJX+vLYQ3+YOIHHhXTXYl93ojwVGosVE5tGFFwfxCF7LE7s3K5w/
9+
A8frWXsfvZzsXipOXcUauIUvmPyMn7FDaoWRIJ8yvlfVFitpOu4/SDk8ZHFORjIA
10+
9SxyPTWlTm8GiiZkQ7WYMnDAkO8MGqjkkv0CAwEAAaNjMGEwDwYDVR0TAQH/BAUw
11+
AwEB/zAdBgNVHQ4EFgQU9/X/DR4yidenar+IRB1/tZWzQz0wDgYDVR0PAQH/BAQD
12+
AgEGMB8GA1UdIwQYMBaAFPlQxJE+KraVWm+KrVoJK8RibV1wMA0GCSqGSIb3DQEB
13+
CwUAA4IBAQAcx+7nMeT8hPZfm7CtcbGQLHJAI4LPIZE3Tcmf5Q0kE7S4lM5uWPge
14+
/rWDFG5sR4w2KL7SZgm5pR2rD/qXIYvTTCOgUpmpaLIFoUEO+X9hnKDtrJl7dep3
15+
BDe5P6L8ol7Qr38uOP9vOkVdKwHcmHOZr9aNHasTL9vOUy5jnQmTm6u9LKi5mokF
16+
w13QB/sa4tpiAMbj6mKqkAHl9WIlhZ/6G/c4IDMs8kzCtszpdNvcj1dw4QSPgg2L
17+
IIpPoWHmD3YYNJts0F9Ytc1E2fkR/J6GurhugtVT6J6DZLG9oftb254l9RGsYsS0
18+
XqIHNbeNF5e6SuN7DpH1IJFNr1g9/zVd
1919
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)