Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Reference-vector checksums cover exact producer bytes on every CI platform.
tests/fixtures/reference/swtpm-nv-certify-0.7.3/** -text
tests/fixtures/reference/swtpm-nv-certify-0.7.3/*.bin binary
# tpm2_nvreadpublic emits this terminal blank line; retain the checksummed output.
tests/fixtures/reference/swtpm-nv-certify-0.7.3/nv-public.yaml whitespace=-blank-at-eof
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- TPM NV-certify wire parsing now delegates to Agent Manifest 0.11.2 instead of
maintaining a second `TPMS_ATTEST`/`TPMS_NV_CERTIFY_INFO` parser in cMCP.
The public `parse_nv_certify` return shape and `ValueError` contract remain
intact. The shared parser also makes cMCP accept valid size-prefixed
`TPM2B_ATTEST` transport framing, reject undeclared bytes after `nvContents`,
and verify AK signatures over the canonical inner `TPMS_ATTEST` rather than
over the transport length prefix. A genuine swtpm-produced two-certify
reference pair exercises the complete chain,
signature, phase, index, and extend-relation path. The synthetic fixture CA is
test trust only and makes no hardware-provenance or vendor-enrollment claim.

- Removed AGT/`agent_os` from the production dependency graph. cMCP now owns the
runtime call and response enforcement path; AGT remains isolated to CI and
release governance verification. Legacy `agent_os_version` bundle metadata is
Expand Down
9 changes: 8 additions & 1 deletion docs/spec/tpm-security-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,14 @@ Because extends accumulate, one certified value cannot be checked against anythi

**P2 is now implemented.** Collection is `cmcp_runtime.tee.measurement.certify_and_extend_gateway_measurement`, appraisal is `cmcp_verify.nv_certify.verify_gateway_measurement`, and startup wires both at step 3b. Only the platform attestation key is used to certify: a transient key would give a verifiable signature with no provenance, which is worse than an honest absence because it looks like evidence, so a platform without a certified key falls back to the unsigned extend and ships no evidence at all.

`agent_manifest.verify_tpm_quote` cannot appraise this, because it rejects any attest type that is not `TPM_ST_ATTEST_QUOTE` and its parser assumes a `TPML_PCR_SELECTION` union. The certificate chain is still delegated to `agent_manifest.verify_cert_chain`; only the `TPM_ST_ATTEST_NV` and `TPMT_SIGNATURE` wire formats are local, tracked upstream as agentrust-io/agent-manifest#255.
Agent Manifest 0.11.2 is the wire-format authority for this path:
`parse_tpm_nv_certify` parses and type-checks the signed common header plus
`TPMS_NV_CERTIFY_INFO`, `parse_tpmt_signature` parses the signature envelope, and
`verify_cert_chain` validates the supplied AK chain against verifier-pinned roots.
cMCP verifies the typed signature with that AK and owns the gateway-specific
two-certify phase binding, same-index requirement, expected digest, and extend
relation. `agent_manifest.verify_tpm_quote` remains quote-specific and is not used
to appraise an NV certification.

**What P2 still does not give you.** The appraisal proves the gateway extended a specific digest into a specific index. It does not prove that digest corresponds to *known-good* code unless the relying party supplies an expected value; without one, `verify_gateway_measurement` reports the pair as internally consistent and says so in its details rather than implying more. Deciding what the expected digest should be for a given release is a release-engineering question, not a TPM one.

Expand Down
12 changes: 8 additions & 4 deletions docs/testing/hardware-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,14 @@ With both fixed, the following hold on hardware:
`TPMT_SIGNATURE`. A NULL scheme resolves to the key's own, RSASSA/SHA-256 here.
- **The platform AK at `0x81000003` can sign an NV certify.** This was an open
question, since it is a restricted signing key; the answer is yes.
- **`parse_nv_certify`'s field offsets are correct against a real blob.** This was
the highest-risk item, as the offsets came from the TCG structures spec and had
never met real bytes. `indexName`, `offset` and `nvContents` all parse, and
`nvContents` equals the value returned by `TPM2_NV_Read`.
- **The signed NV field layout was checked against a real blob.** This was the
highest-risk item, as the offsets came from the TCG structures spec and had
never met real bytes. `indexName`, `offset` and `nvContents` all parsed, and
`nvContents` equalled the value returned by `TPM2_NV_Read`. That run exercised
cMCP's then-local parser. cMCP's public `parse_nv_certify` adapter now delegates
wire parsing to `agent_manifest.parse_tpm_nv_certify`; the committed swtpm
reference pair independently exercises that current boundary without adding a
hardware-provenance claim.
- The extend relation holds on hardware across two consecutive starts: run 1
provisioned the index and run 2 reused it, with run 2's `pre` equal to run 1's
`post`, which is the accumulation the two-certify design exists to handle.
Expand Down
7 changes: 5 additions & 2 deletions src/cmcp_runtime/tee/measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@
The certify path was validated in the same session, after that run found two
defects in it: the ``nv_certify`` call omitted the required ``in_scheme`` and
``size`` arguments, and a freshly provisioned index cannot be certified at all. Both
are fixed; the platform AK does sign an NV certify, and the parser's field offsets
are correct against a real blob. See docs/testing/hardware-validation.md.
are fixed; the platform AK does sign an NV certify, and its signed field layout
matched the value read from the hardware index. That run exercised cMCP's
then-local parser. The current adapter delegates to Agent Manifest, with the
committed swtpm reference pair independently exercising that parser boundary but
making no new hardware-provenance claim. See docs/testing/hardware-validation.md.

## Predictability is deliberately left to the verifier

Expand Down
111 changes: 51 additions & 60 deletions src/cmcp_verify/nv_certify.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,19 @@
would already fail the chain check, but making the role explicit means a verifier
never has to infer it from ordering.

## Why this is not delegated to agent-manifest

``agent_manifest.verify_tpm_quote`` rejects any attest type that is not
``TPM_ST_ATTEST_QUOTE``, and ``parse_tpm_quote`` assumes the attested union is a
``TPML_PCR_SELECTION`` followed by a PCR digest. An NV certify carries a
``TPMS_NV_CERTIFY_INFO`` instead, so neither can read it. The certificate chain
*is* delegated (``agent_manifest.verify_cert_chain``), matching how
:mod:`cmcp_verify.sev_snp` and :mod:`cmcp_verify.tdx` already work. Teaching
agent-manifest ``TPM_ST_ATTEST_NV`` is tracked in agentrust-io/agent-manifest#255,
alongside the same gap for ``TPMT_SIGNATURE``.
## Boundary with agent-manifest

Agent Manifest owns the TPM wire formats: ``parse_tpm_nv_certify`` parses the
signed common header and the ``TPMS_NV_CERTIFY_INFO`` union, accepts bare
``TPMS_ATTEST`` and size-prefixed ``TPM2B_ATTEST`` transport framing, and requires
the union payload to consume the complete inner structure. Its returned
``attest.raw`` is the exact inner byte range signed by the attestation key.

cMCP keeps the gateway-specific policy: the two-certify phase bindings, same-index
check, expected gateway digest, and extend relation. It also preserves the public
``parse_nv_certify`` compatibility adapter and performs signature verification
against the certified AK. Certificate-chain and TPM signature-envelope parsing are
delegated to Agent Manifest as well.
"""

from __future__ import annotations
Expand All @@ -50,13 +53,17 @@
from dataclasses import dataclass, field
from typing import Any

from agent_manifest import parse_tpmt_signature
from agent_manifest import TPM_ST_ATTEST_NV as _TPM_ST_ATTEST_NV
from agent_manifest import (
TpmNvCertify,
TpmVerificationError,
parse_tpm_nv_certify,
parse_tpmt_signature,
)

# TPMS_ATTEST header constants.
_TPM_GENERATED_VALUE = 0xFF544347
TPM_ST_ATTEST_NV = 0x8014
_CLOCK_INFO_LEN = 17
_FIRMWARE_VERSION_LEN = 8
# Preserve the module-level constant imported by existing cMCP callers/tests while
# taking its value from the canonical wire-format library.
TPM_ST_ATTEST_NV = _TPM_ST_ATTEST_NV

# TPM2_ALG_ID digests a signature may use.
_ALG_SHA1 = 0x0004
Expand Down Expand Up @@ -110,50 +117,32 @@ def certify_qualifying_data(nonce: bytes, phase: bytes) -> bytes:
return hashlib.sha256(b"".join(parts)).digest()


def _read_u16(buf: bytes, pos: int) -> tuple[int, int]:
if pos + 2 > len(buf):
raise ValueError("TPMS_ATTEST truncated reading a 16-bit field")
return int.from_bytes(buf[pos : pos + 2], "big"), pos + 2
def _parse_nv_certify(attest: bytes) -> TpmNvCertify:
"""Use Agent Manifest's parser while preserving cMCP's ``ValueError`` API."""
try:
return parse_tpm_nv_certify(attest)
except TpmVerificationError as exc:
raise ValueError(str(exc)) from exc


def _read_2b(buf: bytes, pos: int) -> tuple[bytes, int]:
size, pos = _read_u16(buf, pos)
if pos + size > len(buf):
raise ValueError("TPMS_ATTEST truncated reading a sized buffer")
return buf[pos : pos + size], pos + size
def _as_nv_certify_info(parsed: TpmNvCertify) -> NvCertifyInfo:
return NvCertifyInfo(
qualifying_data=parsed.attest.qualifying_data,
index_name=parsed.info.index_name,
offset=parsed.info.offset,
nv_contents=parsed.info.nv_contents,
)


def parse_nv_certify(attest: bytes) -> NvCertifyInfo:
"""Parse a ``TPMS_ATTEST`` whose attested union is ``TPMS_NV_CERTIFY_INFO``.
"""Parse a bare or size-prefixed TPM NV certification.

Layout after the common header is ``indexName`` (TPM2B_NAME), ``offset``
(UINT16), then ``nvContents`` (TPM2B_MAX_NV_BUFFER). Raises ``ValueError`` on
anything malformed, including a structure that is not an NV certify, so a quote
cannot be passed here by mistake and silently appraised.
Wire parsing is delegated to :func:`agent_manifest.parse_tpm_nv_certify`.
``ValueError`` and the cMCP ``NvCertifyInfo`` return shape are retained for
compatibility. A quote, truncated structure, or structure with undeclared
trailing data is rejected rather than partially appraised.
"""
if len(attest) < 6:
raise ValueError("TPMS_ATTEST too short")
magic = int.from_bytes(attest[0:4], "big")
if magic != _TPM_GENERATED_VALUE:
raise ValueError(f"TPMS_ATTEST magic is not TPM_GENERATED (magic={magic:#x})")
attest_type, pos = _read_u16(attest, 4)
if attest_type != TPM_ST_ATTEST_NV:
raise ValueError(
f"attestation is not an NV certify (type={attest_type:#x}, "
f"expected {TPM_ST_ATTEST_NV:#x})"
)
_qualified_signer, pos = _read_2b(attest, pos) # TPM2B_NAME
qualifying_data, pos = _read_2b(attest, pos) # extraData
pos += _CLOCK_INFO_LEN + _FIRMWARE_VERSION_LEN
index_name, pos = _read_2b(attest, pos) # TPM2B_NAME of the NV index
offset, pos = _read_u16(attest, pos)
nv_contents, pos = _read_2b(attest, pos) # TPM2B_MAX_NV_BUFFER
return NvCertifyInfo(
qualifying_data=qualifying_data,
index_name=index_name,
offset=offset,
nv_contents=nv_contents,
)
return _as_nv_certify_info(_parse_nv_certify(attest))


def build_envelope(
Expand Down Expand Up @@ -259,10 +248,12 @@ def fail(reason: str, **extra: str) -> NvCertifyResult:

# 2. Structure and attest type.
try:
pre = parse_nv_certify(pre_attest)
post = parse_nv_certify(post_attest)
pre_parsed = _parse_nv_certify(pre_attest)
post_parsed = _parse_nv_certify(post_attest)
except ValueError as exc:
return fail("malformed_nv_certify", error=str(exc))
pre = _as_nv_certify_info(pre_parsed)
post = _as_nv_certify_info(post_parsed)
verified.append("structure")

# 3. AK certificate chain to a pinned root, delegated to agent-manifest.
Expand All @@ -284,13 +275,13 @@ def fail(reason: str, **extra: str) -> NvCertifyResult:

# 4. Both signatures, against the certified AK.
try:
for label, blob, sig in (
("pre", pre_attest, pre_sig),
("post", post_attest, post_sig),
for label, attestation, sig in (
("pre", pre_parsed, pre_sig),
("post", post_parsed, post_sig),
):
parsed = parse_tpmt_signature(sig)
parsed_signature = parse_tpmt_signature(sig)
try:
_verify_signature(ak_public, parsed, blob)
_verify_signature(ak_public, parsed_signature, attestation.attest.raw)
except Exception as exc: # noqa: BLE001
return fail("signature_invalid", which=label, error=str(exc))
except Exception as exc: # noqa: BLE001
Expand Down
85 changes: 85 additions & 0 deletions tests/fixtures/reference/swtpm-nv-certify-0.7.3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# swtpm NV-certify reference pair

These files are an independent-producer reference for cMCP's gateway-measurement
appraisal path. They were emitted by `swtpm` 0.7.3 and `tpm2-tools` 5.6 in an
Ubuntu 24.04 container, using a restricted RSA-2048 attestation key configured for
RSASSA/SHA-256. Neither cMCP nor Agent Manifest produced the attestation or
signature bytes.

The pair certifies a 32-byte `TPM_NT_EXTEND` index immediately before and after
extending the gateway digest:

```text
post-contents = SHA256(pre-contents || gateway-digest)
```

Both attestations are bare 173-byte `TPMS_ATTEST` structures with type
`TPM_ST_ATTEST_NV` (`0x8014`). Both signatures are 262-byte marshalled
`TPMT_SIGNATURE` values: RSASSA (`0x0014`), SHA-256 (`0x000b`), and a 256-byte
signature. `nv-public.yaml` is the output of `tpm2_nvreadpublic 0x01500018`; its
Name is checked against the Name signed into both attestations.

## Signed bindings

- Verifier nonce: 32 bytes of `a5`.
- Pre qualifying data:
`ac2bc955b7d97a5589f9a6c48db86f87aea9d9af22e43cc97330f7b560145fa3`.
- Post qualifying data:
`230587d8162f6a14fb8573d2b3fddec4b98413ffad0f83e804aff3740d8bfa8c`.
- NV handle used by the producer: `0x01500018`.
- Certified offset and size: `0` and `32` bytes.
- Index Name:
`000bcf69802ad7625fffd515aecef934a1632ca6c7df36bf5a4e241d33701465a854`.
- Gateway digest:
`4ea5ee68fea05586106890ded5733820bb77d919cda27bc4b8139b7cd33b8889`.

The qualifying data are cMCP's length-prefixed, phase-separated hashes for
`pre` and `post`. The first extend used `seed-event.bin` because a newly defined
extend index is uninitialized and cannot yet be certified.

## Certificate construction and assurance boundary

`ak-public.pem` is the exact public key returned by `tpm2_readpublic` for the swtpm
AK. `ak-cert.pem` is a test certificate made afterwards by placing that public key
under `synthetic-root.pem`; the test asserts that the certificate and TPM output
contain identical public keys. The synthetic CA private key and all TPM state,
contexts, and private material were destroyed and are not committed.

This corpus proves that the parser and appraisal path accept one independently
emitted software-TPM wire image, authenticate both signatures under the included
test chain, bind the two phases and index Name, and check the extend relation. It
does **not** prove a physical TPM, vendor enrollment, EK-to-AK credential
activation, non-exportability, hardware key residency, requester/TPM co-location,
boot state, runtime integrity, or safe application behavior. A software TPM may
also be operated as a remote signing oracle.

## Producer sequence

The essential commands were:

```sh
tpm2_createek -G rsa -c ek.ctx -u ek.pub
tpm2_createak -C ek.ctx -G rsa -g sha256 -s rsassa \
-c ak.ctx -u ak.pub -n ak.name
tpm2_flushcontext -t

tpm2_nvdefine 0x01500018 -C o -g sha256 -s 32 \
-a 'ownerread|ownerwrite|nt=extend'
tpm2_nvextend 0x01500018 -C o -i seed-event.bin

tpm2_nvcertify -C ak.ctx -c o -g sha256 -s rsassa -f tss \
-q ac2bc955b7d97a5589f9a6c48db86f87aea9d9af22e43cc97330f7b560145fa3 \
--size 32 --offset 0 --attestation pre-attest.bin \
-o pre-tpmt-signature.bin 0x01500018

tpm2_nvextend 0x01500018 -C o -i gateway-digest.bin

tpm2_nvcertify -C ak.ctx -c o -g sha256 -s rsassa -f tss \
-q 230587d8162f6a14fb8573d2b3fddec4b98413ffad0f83e804aff3740d8bfa8c \
--size 32 --offset 0 --attestation post-attest.bin \
-o post-tpmt-signature.bin 0x01500018
```

`tpm2_print` 5.6 does not understand the `TPM_ST_ATTEST_NV` union. The tests
therefore parse the signed structures with the released Agent Manifest parser and
independently compare the signed Name with `tpm2_nvreadpublic` output.
12 changes: 12 additions & 0 deletions tests/fixtures/reference/swtpm-nv-certify-0.7.3/SHA256SUMS
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
6f13324e7cd6d5302bc8af2d66321c8597bb04256cba31660da403534a545dd5 ak-cert.pem
2695b54c92d2fc515cc3769ddc93682977a2bc073900ff3300a473f5f7d9bd10 ak-public.pem
e1ff313ca44d96a8e827915e3a004a8c72d1ca48844ab3f4a8ac5707d4bbd19c gateway-digest.bin
1c39e6d7f1fbbf5c86142288c52d8c0d19438a7ab5a303ef62517f1edd6edc2a nv-public.yaml
d6f807d21ea2d255897451c0e3ec528648a51b2d58097fec891fd654b5d27e7e post-attest.bin
eba6ca529787d3a63e04eebacf829f5b86cc3bd30de7112269116ba53edbdd0d post-contents.bin
5e22d7c3220dfd5b0f9b029d57d65b1a5c80d1235f7d6d12d0d1564a1a582c0b post-tpmt-signature.bin
d94c9c11c152e16a57c2daa7090f57da94b068b0e43511d73bd6fa5dc1b26e29 pre-attest.bin
25496e06bd981ee16f2f177f1c69106ff712a77d259ef7616e203bcba572b523 pre-contents.bin
03288dc5973a51bd44ff47b156a524be1f837ea69d3cdfb3a08827afeef37d9e pre-tpmt-signature.bin
ee20f2868946b0095c0bd65d8564237cc5cc1debea71c5dc3ead281124ae05f6 seed-event.bin
8f33533725b2db95f1e3c7b8bf0240923fff6b34c4fcf88d7b72589d89b0fddc synthetic-root.pem
13 changes: 13 additions & 0 deletions tests/fixtures/reference/swtpm-nv-certify-0.7.3/ak-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB+DCCAZ8CAQIwCgYIKoZIzj0EAwIwJDEiMCAGA1UEAwwZY01DUCBzd3RwbSBy
ZWZlcmVuY2Ugcm9vdDAeFw0yNjA5MDIwMjIyNDdaFw0zNjA4MzAwMjIyNDdaMCIx
IDAeBgNVBAMMF2NNQ1Agc3d0cG0gcmVmZXJlbmNlIEFLMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEA1thCyGmNJrEcUYRUXsU4qEg0j395Qc4HC/E/1AZ/
OQ/G1TADykn/oZVkJwF7cXcJeTDakXHzNBs5E6w1g1ejdOF6j7USiTgu1VrMLxhB
aJlg3E/5YwCStKbOXpMDj0hXEC+3U2k4EhqjuKp3GSylUtvbloAAChF/0iRoOxyV
XFm4O6rVZdMXz9U+/7Jymms9Xqqvn9zTLkU+XBnaxpWigstDoC5CBcbAtycXZE1k
/C7QCyTZvrimqmtNlCDGmP8hyK+bNAuBWvaeE/JwWIhZpr5dWapi4WBKp7hO4K9G
W5UfzWEz2vcG11MXO4aEO2Q1MbSWlDG97E6yYHNg2/xYtwIDAQABMAoGCCqGSM49
BAMCA0cAMEQCIB3DLSZTnN/U8FUEUHrRd7FiKQRZT8xEaHCesgtaDCK9AiB8A7lK
wMfkjnfckyK4Yxe8eR0fiJtS6XEBfpQKrGp8Eg==
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1thCyGmNJrEcUYRUXsU4
qEg0j395Qc4HC/E/1AZ/OQ/G1TADykn/oZVkJwF7cXcJeTDakXHzNBs5E6w1g1ej
dOF6j7USiTgu1VrMLxhBaJlg3E/5YwCStKbOXpMDj0hXEC+3U2k4EhqjuKp3GSyl
UtvbloAAChF/0iRoOxyVXFm4O6rVZdMXz9U+/7Jymms9Xqqvn9zTLkU+XBnaxpWi
gstDoC5CBcbAtycXZE1k/C7QCyTZvrimqmtNlCDGmP8hyK+bNAuBWvaeE/JwWIhZ
pr5dWapi4WBKp7hO4K9GW5UfzWEz2vcG11MXO4aEO2Q1MbSWlDG97E6yYHNg2/xY
twIDAQAB
-----END PUBLIC KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
N¥îhþ U†hÞÕs8 »wÙÍ¢{ĸ›|Ó;ˆ‰
10 changes: 10 additions & 0 deletions tests/fixtures/reference/swtpm-nv-certify-0.7.3/nv-public.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
0x1500018:
name: 000bcf69802ad7625fffd515aecef934a1632ca6c7df36bf5a4e241d33701465a854
hash algorithm:
friendly: sha256
value: 0xB
attributes:
friendly: ownerwrite|nt=0x1|ownerread|written
value: 0x20020042
size: 32

Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ý.lLÈ0nÃ.S—=ÛÚÊBb:‰¨‚/—]x#V‘
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Äÿ‰L:ˆI´ì«áÍÜ;ç¿Ãþã+ˆi™æãžy“‡
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ÇÅêyóëT+%Îi×û;Ýש‹4¹ÖôÆäë¡âӏ
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBrDCCAVOgAwIBAgIUE6+q70duBW8wyyYiMNYYryxgsbQwCgYIKoZIzj0EAwIw
JDEiMCAGA1UEAwwZY01DUCBzd3RwbSByZWZlcmVuY2Ugcm9vdDAeFw0yNjA5MDIw
MjIyNDdaFw0zNjA4MzAwMjIyNDdaMCQxIjAgBgNVBAMMGWNNQ1Agc3d0cG0gcmVm
ZXJlbmNlIHJvb3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARANBe7aD3FQdTm
oA/IuU1xZPPhIJt8wqeUF2VdIzK4fvta4lfLgsDT45cguqlfIDKgBF9UG+MKCa8k
MHECDIP8o2MwYTAdBgNVHQ4EFgQUzLy1poKFkMXlj9OICF8WmHXhjOYwHwYDVR0j
BBgwFoAUzLy1poKFkMXlj9OICF8WmHXhjOYwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwIDRwAwRAIgK7g2vAGhxc6KX/ZbxZKHf9U8
J7AWDHb2IyvoK1mQXqQCIFB2viPKPbnUJQ6EXxmpknwAzx87vzeXE2CTCC4M2wEW
-----END CERTIFICATE-----
Loading
Loading