From 6038234f61aa1360cbf498370c9ef0638ab18cc2 Mon Sep 17 00:00:00 2001 From: user <303926+HarryR@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:07:55 +0800 Subject: [PATCH] Added alibaba trust client notes --- experiments/alibaba/.gitignore | 4 + experiments/alibaba/NOTES.md | 552 ++++++++++++++++++ .../alibaba/alibaba-trust-us-east-1.sh | 144 +++++ experiments/alibaba/aliyun-ekmf-ca.crt | 93 +++ experiments/alibaba/aliyun-root-ca.crt | 81 +++ 5 files changed, 874 insertions(+) create mode 100644 experiments/alibaba/.gitignore create mode 100644 experiments/alibaba/NOTES.md create mode 100644 experiments/alibaba/alibaba-trust-us-east-1.sh create mode 100644 experiments/alibaba/aliyun-ekmf-ca.crt create mode 100644 experiments/alibaba/aliyun-root-ca.crt diff --git a/experiments/alibaba/.gitignore b/experiments/alibaba/.gitignore new file mode 100644 index 0000000..aafeef9 --- /dev/null +++ b/experiments/alibaba/.gitignore @@ -0,0 +1,4 @@ +t-trustclient-extracted +trustagent-binaryninja +trustagent-hexrays +t-trustclient.deb diff --git a/experiments/alibaba/NOTES.md b/experiments/alibaba/NOTES.md new file mode 100644 index 0000000..e79890f --- /dev/null +++ b/experiments/alibaba/NOTES.md @@ -0,0 +1,552 @@ +# Alibaba Cloud vTPM Attestation - Research Notes + +## Overview + +Alibaba Cloud (Aliyun) ECS security-enhanced instances include a vTPM (TPM 2.0 compatible). +The trust agent (`t-trustclient`) runs on the instance and handles attestation automatically. + +## Certificate Chain (EK) + +Downloaded from public OSS bucket. Chain verifies cleanly. + +``` +Root: C=CN, O=Aliyun, OU=Aliyun TPM Root CA, CN=Aliyun TPM Root CA + RSA 2048, self-signed, sha384WithRSA, valid until 2030 + URL: https://aliyun-tpm-ca.oss-cn-beijing.aliyuncs.com/pki001/root-ca.crt + +Intermediate: C=CN, O=Aliyun, OU=Aliyun TPM Endorsement Key Manufacture CA, CN=Aliyun TPM EKMF CA + RSA 2048, signed by root, sha384WithRSA, valid until 2030 + URL: https://aliyun-tpm-ca.oss-cn-beijing.aliyuncs.com/pki001/ekmf-ca.crt + CRL: https://aliyun-tpm-ca.oss-cn-beijing.aliyuncs.com/pki001/root-ca.crl +``` + +No AK/AIK certificates found at the OSS bucket (tried various guesses, all 403). +Bucket listing is access-denied. + +## Trust Agent Package + +Available from public OSS buckets per region: +``` +http://trustclient-${REGION_ID}.oss-${REGION_ID}.aliyuncs.com/download/linux/ubuntu/x86_64/${VERSION}/t-trustclient-${VERSION}-x86_64.deb +``` + +Current version: 1.1.0 (as of 2026-02-07) +Available in: cn-beijing, cn-hangzhou, cn-shanghai, us-east-1, ap-southeast-1 (NOT us-west-1) + +### Package Contents +``` +/etc/ali_trust_net.conf # config +/usr/local/bin/trust-agent # main binary +/usr/lib/systemd/system/t-trustclient.service # systemd unit +/usr/lib/libtrust.so.1.0.0 # core trust library +/usr/lib/libtrust_tpm.so.1.0.0 # TPM operations +/usr/lib/libtrust_network.so.1.0.0 # network/API calls (statically linked against libstdc++, libcurl, libssl, etc.) +/usr/lib/libtpm2-openssl.so.1.0.0 # TPM2 OpenSSL provider +/usr/lib/libtpm2-tools.so.1.0.0 # TPM2 tools +/usr/lib/libtss2-tcti-device.so.1.0.0 # TSS2 TCTI device +``` + +Built from: `trustclient-opensource/third_party/ali-trust-sdk/` (source paths in binary) +Key source files referenced: `tpm_net_api.cpp`, `tpm_pop_visitor.cpp`, `tpm_http_visitor.cpp` + +## Configuration (`ali_trust_net.conf`) + +Key settings: +- `REGION_ID` - auto-detected from instance metadata +- `DEFAULT_SERVICE_ENDPOINT` / `TRUSTED_SERVER_ENDPOINT` - e.g. `trusted-server-vpc.cn-hangzhou.aliyuncs.com` +- `QUOTE_SERVER_ENDPOINT` - separate endpoint for quote submission +- `AIKSS_SERVER_ENDPOINT` - separate endpoint for AIK signing service +- `POP_ENABLED=TRUE` - use Alibaba Cloud POP API gateway (vs direct HTTP) +- `HTTP_ENABLED` - for direct HTTP mode (bypasses POP) +- `INCREMENT_IMA=FALSE` - incremental IMA log submission +- `ACCESS_KEY` / `ACCESS_SECRET` - for classic credential mode + +## Authentication & Visitor Architecture + +Two visitor implementations (`TpmVisitor` is the base interface): + +### TpmPopVisitor (default, `POP_ENABLED=TRUE`) +- Uses Alibaba Cloud POP (Platform of Platforms) API gateway +- Authenticates via `PopVisitor::validateCredential()` / `PopVisitor::refreshCredential()` +- Creates either `VpcCredential` or `ClassicCredential` depending on config +- Calls `yundun-systrust` API actions: `GenerateNonce`, `GenerateAikcert`, `ProduceAikcert`, + `RegisterMessage`, `PutMessage`, `QuoteMessage` + +### TpmHttpVisitor (fallback, `HTTP_ENABLED=TRUE`) +- Direct HTTP POST to `trusted-server-vpc.{region}.aliyuncs.com` +- **No authentication on the HTTP requests themselves** - relies on: + 1. Network-level gating (VPC-only endpoint, `-vpc` suffix) + 2. TPM cryptographic binding (MakeCredential blobs are useless without the real TPM) +- Uses `CurlUtils::http_post` with JSON request/response + +### Credential types +1. **VpcCredential** (default) - uses instance metadata at `http://100.100.100.200/latest/meta-data/ram/security-credentials/` to get temporary `AccessKeyId`, `AccessKeySecret`, `SecurityToken`, `Expiration` +2. **ClassicCredential** - static access key/secret from config + +### Endpoint construction (from `ali_trust_init_tpm_visitor` decompilation) +When no explicit endpoint is configured, constructs: +``` +"trusted-server-vpc." + GuestInfo.region_id + ".aliyuncs.com" +``` +Also reads `AIKSS_SERVER_ENDPOINT` and `QUOTE_SERVER_ENDPOINT` from `NetConfig` singleton. + +## trust-agent Main Flow (from Hex-Rays decompilation) + +``` +main(): + 1. Print "Trust Agent Version: 9a6e56c17362ced8592fb5ca3a509ad59185598d" + 2. Create logger → /var/log/trust-agent + 3. Create scheduler(5 tasks, 1800s interval, 300s initial delay) + 4. ali_trust_tpm_init_context("9a6e56c17362ced8592fb5ca3a509ad59185598d") + 5. Schedule "instance registration" → ali_trust_tpm_register + 6. Schedule "remote attestation" → attestation_loop (sub_BA00) +``` + +### Attestation Loop (runs every 30 minutes) +``` +sub_BA00(): + 1. ali_trust_tpm_generate_aik_cert(1, &aik_context) + → Called EVERY cycle, not just once at boot + → First param=1 may mean "include cert chain" + → If fails: "error while requesting aik cert, errno: %d" + + 2. ali_trust_tpm_generate_quote(aik_context, 0, 0, 0, 3, 1, 0, "e) + → Params: (context, ?, ?, ?, pcr_bank_mask=3?, algo=1, ?, &output) + → If fails: "error while generating quote, errno: %d" + + 3. ali_trust_tpm_attestation(quote, &result) + → Submits quote to server, gets back ali_trust_attest_ra_result_t + → If fails: "error while initiating remote attestation, errno: %d" + + 4. Log: "system trust status: %d" (result[0]) +``` + +## API Flow (from BinaryNinja decompilation of `libtrust_network.so`) + +### Phase 1: Register (`/register`) + +`TpmHttpVisitor::register_inst()` - registers the instance with the trusted server. + +Request params (JSON POST): +- `RequestId` - generated UUID +- `PropertyUuid` +- `InstanceId` +- `InstanceType` +- `PropertyPublicIp` +- `PropertyPrivateIp` +- `PropertyName` +- `PropertyAffiliation` + +Response: `httpStatusCode` + +### Phase 2: AIK Certificate (`/aikcert/produce`) + +`TpmHttpVisitor::aik_cert()` - Privacy CA flow. + +**Confirmed function signature (BinaryNinja):** +```cpp +uint64_t aik_cert( + /* this */, // TpmHttpVisitor, base URL at this+0x70/0x78 + const string& ek_pubkey, // → "EkPubKey" + const string& ek_cert, // → "EkCert" + const string& aik_name, // → "AikName" + const string& cert_request, // → "CertRequest" (CSR) + bool include_cert_chain, // → "IncludeCertChain" (sprintf'd as "%d") + string& out_key_cred_blob, // ← output: "keyCredentialBlob" + string& out_data_cred_blob // ← output: "dataCredentialBlob" +) +``` + +**Confirmed flow (from decompilation):** +1. Constructs URL: `base_url + "/aikcert/produce"` +2. Builds `std::map` with `RequestId`, `EkPubKey`, `EkCert`, `AikName`, + `CertRequest`, `IncludeCertChain` +3. `assemble_params()` → `CurlUtils::http_post()` (plain HTTP, no auth headers) +4. Parses JSON response with `Json::Reader::parse()` +5. Checks `json["httpStatusCode"] == 200` (0xc8) +6. On success: extracts nested `json[...]["keyCredentialBlob"]` → arg7, + `json[...]["dataCredentialBlob"]` → arg8 +7. Returns 0 on success, 0x3003 on any error + +**Interpretation:** Server validates EK cert against Aliyun TPM CA chain, then uses +`TPM2_MakeCredential` to create challenge blobs. Client calls `TPM2_ActivateCredential` +(in `libtrust_tpm.so`) to prove AIK is co-resident with EK. The `CertRequest` (CSR) is +sent so the server can sign it - but the actual signed cert delivery mechanism is still +unclear (may be wrapped in the credential blobs, or may require a follow-up call). + +### Phase 3: Attestation/Quote (`/quote`) + +`TpmHttpVisitor::attestation()` - submits TPM quote evidence. + +**Confirmed function signature:** +```cpp +uint64_t attestation( + /* this */, + const string& file_data, // → "FileData" (TPM quote + IMA log) + ali_trust_attest_ra_result_t& result, // ← output struct + string& request_id_out // ← output: request ID +) +``` + +**Confirmed flow:** +1. Constructs URL: `base_url + "/quote"` (note: uses offset 0x50/0x58, different from aik_cert's 0x70/0x78 - may use `QUOTE_SERVER_ENDPOINT`) +2. Sends `RequestId` + `FileData` +3. Parses JSON, checks `httpStatusCode == 200` +4. Extracts into result struct: + - `systemVerificationResult` → result field (int) + - `programVerificationResult` → result field (int, default=4 if missing) + - `kmoduleVerificationResult` → result field (int, default=4 if missing) + - `nextClientIMAIndex` → result field (uint64) + - `policyProcResult` → optional, if present calls `ali_trust_elem_init_from_c_str` + to parse `procData` into an `ali_trust_elem` + +## Key Functions (from symbol tables) + +### trust-agent binary +- `ali_trust_tpm_init_context` - init with version string +- `ali_trust_tpm_generate_aik_cert` - triggers the AIK cert flow +- `ali_trust_tpm_register` - registers with trusted server +- `ali_trust_tpm_generate_quote` - generates TPM quote +- `ali_trust_tpm_attestation` - submits attestation + +### libtrust.so (core library - abstract interface) +- `ali_trust_quote(nonce, pcr_bank, pcr_selection, policy_effect, policy_action, extra, &output)` - quote with policy params +- `ali_trust_attestation(quote, &result)` - submit attestation, get `ali_trust_attest_ra_result_t` +- `ali_trust_generate_plat_cert` / `ali_trust_renew_plat_cert` - platform certificates +- `ali_trust_generate_app_cert` / `ali_trust_renew_app_cert` - application certificates +- `ali_trust_generate_session_credential` / `ali_trust_verify_session_credential` +- `ali_trust_inspect_plat_stat` - get `ali_trust_attest_ra_status_t` +- `ali_trust_sign`, `ali_trust_encrypt`, `ali_trust_decrypt` +- `ali_trust_create_key`, `ali_trust_import_key`, `ali_trust_export_key` +- `ali_trust_define_sb`, `ali_trust_read_sb`, `ali_trust_write_sb` (sealed blob operations) + +### libtrust_tpm.so (TPM implementation) +Key types (C++ classes under `AlibabaCloud::AliTrust`): +- `TpmPlatformKey` - platform-level key +- `TpmCommonKey` - general purpose key +- `TpmUserImportedKey` - user-imported key +- `TpmPreGeneratedKey` - pre-provisioned key +- `TpmCommonNonVolatile` / `TpmPreGeneratedNonVolatile` - NV storage + +### libtrust_network.so (network layer) +Class hierarchy: +``` +CommonVisitor (base) +├── PopVisitor +│ └── TpmPopVisitor (POP API gateway, authenticated) +└── TpmHttpVisitor (direct HTTP, VPC-only) + +CommonCredential (base) +├── VpcCredential (instance metadata RAM creds) +└── ClassicCredential (static access key/secret) + +NetConfig (singleton) - reads ali_trust_net.conf +GuestInfo (singleton) - instance metadata (region, IPs, etc.) +MachineInfo (singleton) - machine-level info +``` + +Virtual method table (both visitors implement same interface): +- `register_inst(uuid, instance_id, instance_type, public_ip, private_ip, name, &affiliation)` +- `aik_cert(ek_pubkey, ek_cert, aik_name, cert_request, include_chain, &key_blob, &data_blob)` +- `attestation(file_data, &ra_result, &request_id)` + +### Trusted_serverClient operations (POP path, from C++ mangled names) +- `registerMessageCallable` → `/register` equivalent +- `verifyMessageCallable` → `/quote` equivalent +- `updateComponentCallable` +- `unregisterMessageCallable` +- `trustEventsCallable` + +## TDX vs vTPM Attestation + +Alibaba has TWO completely separate attestation paths: + +| Aspect | vTPM | TDX | +|--------|------|-----| +| Endpoint | `trusted-server-vpc.{region}.aliyuncs.com` | `attest.{region}.aliyuncs.com` | +| Auth | VPC-only + POP gateway (or plain HTTP) | Anonymous HTTP POST | +| Response | Structured JSON (PCR values, trust status) | JWT (OIDC-compliant, RS256) | +| JWKS | N/A | `https://attest.cn-beijing.aliyuncs.com/jwks.json` | +| EAT Profile | Not documented | Documented | +| Certificate | AIK cert via Privacy CA flow | N/A (enclave attestation) | + +## OIDC Discovery (TDX path only) + +```json +{ + "issuer": "https://attest.cn-beijing.aliyuncs.com", + "jwks_uri": "https://attest.cn-beijing.aliyuncs.com/jwks.json", + "token_endpoint": "https://attest.cn-beijing.aliyuncs.com/token", + "id_token_signing_alg_values_supported": ["RS256"] +} +``` + +JWKS has one key: RSA, kid=`4653550c-5551-5e6f-92b5-22f530229751` + +## Decompilation Artifacts (Summary) + +See the detailed line-number index in the "Decompilation Artifacts" section below (after the TPM Internals section). + +## TPM Internals (from BinaryNinja decompilation of `libtrust_tpm.so`) + +### TPM Handle Defaults (`TpmPlatformKey` static constants) + +| Handle | Hex Value | Purpose | +|--------|-----------|---------| +| `ekDefaultKeyHandle` | `0x81010001` | EK persistent key (standard TPM2 EK at 0x81010001) | +| `ekDefaultCertHandle` | `0x01c00002` | EK cert NV index (standard TPM2 EK cert NV) | +| `aikDefaultKeyHandle` | `0x81010003` | AIK persistent key (Alibaba-specific) | +| `aikDefaultNameNvHandle` | `0x1001000` | AIK name NV storage (Alibaba-specific) | + +### TPM Device Architecture + +Three-layer abstraction for TPM operations: + +``` +TpmDeviceProxy (dispatcher) +├── TpmToolsOpsImpl (ITpmDeviceOps) +│ └── tpm2_init() → tpm2_set_option(cmd, key, val) → tpm2_run(cmd, buf, size) → flush_tpm_context() +│ └── Uses libtpm2-tools.so (custom, NOT upstream tpm2-tools) +└── TpmSslOpsImpl (ITpmDeviceOps) + └── Uses OpenSSL with libtpm2-openssl provider + └── Provider searched at /usr/lib64 then /usr/lib + └── Operations like decrypt/encrypt/sign via OpenSSL EVP API with TPM keys +``` + +`TpmDeviceProxy::run(cmd_id, option_map, output_elem)`: +- Takes a `tpm_ops_cmd_t` command ID (0-29, 0x1d max) +- Routes to either TpmToolsOpsImpl or TpmSslOpsImpl based on command type +- Holds a vector of `(tpm_ops_type_t, shared_ptr)` pairs +- Acquires `TpmLock` before running (mutex-protected TPM access) + +### AIK Certificate Generation - FULL FLOW (RESOLVED) + +**`TpmAttestationImpl::generate_aik_cert(bool include_chain, _ali_trust_elem& output)`** + +This is the complete Privacy CA flow. Decompiled from line 96987 of the BN export. + +``` +Phase A: Prepare TPM Objects + 1. Parse aikDefaultKeyHandle ("0x81010003") from hex string → uint64 + 2. Create TpmPreGeneratedKey(handle=0x81010003, algorithm=1) + → This is a shared_ptr, represents the AIK key in TPM persistent storage + 3. Parse aikDefaultNameNvHandle ("0x1001000") → uint64 + 4. Create TpmPreGeneratedNonVolatile(nv_index=0x1001000) + → For AIK name storage + +Phase B: Read TPM Public Data + 5. Call virtual method on key object → reads AIK public key from TPM + 6. CryptoUtils::base64_encode(aik_pubkey) → AikPubKey param + 7. Parse ekDefaultCertHandle ("0x01c00002") → uint64 + 8. Create TpmPreGeneratedNonVolatile(nv_index=0x01c00002) → for EK cert + 9. Store objects in TpmObjectManager for lifecycle management + +Phase C: Build network request params & call Privacy CA + 10. Build option map with short keys like "0", "S", "c", "e", etc. + 11. Call server's virtual method (→ visitor.aik_cert) + 12. ali_trust_tpm_net_aik_cert(visitor, &output_params...) + → Network call to /aikcert/produce + → Returns: keyCredentialBlob (var_6e8) and dataCredentialBlob (var_6c8) + +Phase D: Process keyCredentialBlob + 13. CryptoUtils::base64_decode(keyCredentialBlob) → raw credential + 14. Save decoded blob to "cipher_aik_key.dat" (timestamped path) + +Phase E: TPM2 ActivateCredential + 15. TpmDeviceProxy::run(0x19, {"0": session_ctx, "S": session_file}) + → Command 0x19 (25) = StartAuthSession + 16. TpmDeviceProxy::run(0x1a, {"c": "e", "S": session_file}) + → Command 0x1a (26) = ActivateCredential + → "c" is credential file, "e" is EK handle + → TPM proves AIK is co-resident with EK, outputs the wrapped secret + +Phase F: Decrypt AIK certificate with activated secret + 17. TpmDeviceProxy::run(0x07, {"C": session, "c": cred_file, "i": input, "P": password, "o": output}) + → Command 7 = Decrypt/Decapsulate operation + → Writes decrypted secret to "plain_aik_key.dat" + 18. TpmDeviceProxy::run(0x18, {...}) + → Command 0x18 (24) = FlushContext (cleanup) + 19. CryptoUtils::base64_decode(dataCredentialBlob) → raw encrypted blob + 20. FileUtils::read_file_to_string("plain_aik_key.dat") → AES key + +Phase G: AES Decrypt the certificate + 21. Parse the decoded dataCredentialBlob: + - bytes[0:4] = unknown (version/magic, 4 bytes skipped) + - bytes[4:20] = 16-byte AES IV + - bytes[20:] = AES ciphertext (encrypted AIK certificate PEM) + 22. CryptoUtils::aes_decrypt(ciphertext, len, aes_key, iv, plaintext, &output_len) + → aes_key = the activated credential secret from step 17 + → Decrypts to PEM certificate text + +Phase H: Cache the AIK certificate + 23. CryptoUtils::trim_certs(decrypted_pem) → clean up whitespace/formatting + 24. ali_trust_elem_init_from_c_str(pem_data) → store in output elem + 25. TpmAttestationImpl::cache_aik_certs(pem_data) + → split_pem_cert() to separate cert chain + → Store individual certs as DER in TPM NV indices +``` + +**KEY INSIGHT:** The AIK certificate is signed server-side and delivered encrypted in the +`dataCredentialBlob`. The `keyCredentialBlob` contains a TPM2_MakeCredential wrapper around +an AES key. Only the real TPM (with the real EK) can unwrap the AES key and decrypt the cert. +This is a textbook Privacy CA implementation with AES envelope encryption. + +**There is NO second round-trip.** The entire flow is: one API call → two blobs → TPM unwrap → AES decrypt → PEM cert. + +### AIK Certificate Renewal + +`TpmAttestationImpl::renew_aik_cert(bool include_chain, _ali_trust_elem& output)` (line 94901): +1. Creates new `TpmPreGeneratedKey` with `aikDefaultKeyHandle` +2. Calls `TpmKey::set_auto_clear()` on the key (marks for cleanup) +3. Creates new `TpmPlatformKey` (re-provisions the platform key) +4. Calls `remove_cached_aik_certs()` to clear old certs from NV storage +5. Then proceeds with the same Privacy CA flow + +### AIK Certificate Caching (where the cert ends up) + +`TpmAttestationImpl::cache_aik_certs(const string& pem_data)` (line 96508): +1. `CryptoUtils::split_pem_cert()` - splits PEM bundle into individual certs +2. Converts each cert from PEM to DER (`CryptoUtils::cert_pem2der()`) +3. Stores the DER certs in TPM NV indices +4. The split suggests the cert chain may have multiple certs (AIK cert + issuer chain) + +### Certificate Expiry Checking + +In the outer `ali_trust_tpm_generate_aik_cert()` wrapper (line 68522): +1. First checks `capability(6)` - if supported, goes straight to full cert generation +2. Otherwise: reads cached AIK cert, calls `CryptoUtils::split_pem_cert()` +3. `CryptoUtils::check_cert_expiry(cert, len, &threshold)` with threshold = `time() + 0x15180` + - 0x15180 = 86400 seconds = **24 hours** +4. If cert expires within 24 hours → trigger full renewal +5. If cert is still valid → use cached version (`ali_trust_elem_move`) +6. This explains why `generate_aik_cert` is called every 30 minutes but doesn't always hit the network + +### Quote Generation + +`TpmAttestationImpl::generate_quote()` (line 95121): +- PCR selection: `"sha1:0,1,2,3,4,5,6,7,8,9,10+sha256:0,1,2,3,4,5,6,7,8,9,10"` (both SHA-1 and SHA-256 banks, PCRs 0-10) +- Output file: `pcrlist.dat` (timestamped) +- `TpmDeviceProxy::run(0x0b, option_map)` → Command 0x0b (11) = **TPM2_Quote** +- Option keys: `"o"` = output file, `"#"` = PCR selection +- Also handles IMA (Integrity Measurement Architecture) log: + - Reads `/sys/kernel/security/ima/binary_runtime_measurements` + - Saves to `ima_log.dat` + +### Attestation Submission + +`TpmAttestationImpl::attestation()` (line 94126): +- Simple tailcall: `ali_trust_tpm_net_attestation(visitor, result, ...)` +- Delegates entirely to the network layer's `attestation()` method + +### TPM Command ID Map (partial, from `TpmDeviceProxy::run` calls) + +| CMD ID | Hex | Operation | +|--------|-----|-----------| +| 7 | 0x07 | Decrypt/Decapsulate (via TpmSslOpsImpl) | +| 11 | 0x0B | TPM2_Quote | +| 24 | 0x18 | TPM2_FlushContext | +| 25 | 0x19 | TPM2_StartAuthSession | +| 26 | 0x1a | TPM2_ActivateCredential | +| 29 | 0x1d | (max valid command) | + +### `CryptoUtils` Functions Identified + +| Function | Purpose | +|----------|---------| +| `base64_encode(data, len, &output_string)` | Base64 encode | +| `base64_decode(string, buf, buf_len, &output_elem)` | Base64 decode | +| `aes_decrypt(ciphertext, len, key, iv, plaintext, &out_len)` | AES decryption | +| `split_pem_cert(pem_bundle, &cert, &chain)` | Split PEM chain | +| `trim_certs(pem_string)` | Clean up PEM formatting | +| `check_cert_expiry(cert, len, &threshold_time)` | Check X.509 expiry | +| `pubkey_from_pem_cert(pem, buf, len, &out_len)` | Extract public key | +| `cert_der2pem(der_elem, &pem_elem)` | DER to PEM conversion | +| `cert_pem2der(pem_elem, &der_elem)` | PEM to DER conversion | +| `hash_sha256(data, len, &output_string)` | SHA-256 hash | + +## Open Questions (Updated) + +1. ~~**What happens after ActivateCredential?**~~ **RESOLVED.** Full flow documented above. + The activated credential secret is used as an AES key to decrypt `dataCredentialBlob`, + which contains the AIK certificate PEM. No second round-trip needed. + +2. **Can we extract the AIK cert independently?** The cert is cached in TPM NV indices + (via `cache_aik_certs`) and also temporarily written to disk as files. The DER-encoded + certs are stored in NV. With `tpm2_nvread` it should be possible to extract them. + +3. **What CA signs the AIK cert?** Still unknown from decompilation alone. The `CertRequest` + (CSR) parameter in the API suggests the server signs it. The `AIKSS_SERVER_ENDPOINT` + config option suggests a dedicated AIK Signing Service. The cert chain is split and + cached, so the response likely includes the full chain (AIK cert + intermediate + root). + +4. **Is `ali_trust_generate_plat_cert` useful?** Still needs investigation. + +5. **Can we use the quote data for non-interactive verification?** The quote generation + uses standard TPM2_Quote with SHA-1+SHA-256 banks, PCRs 0-10. If we can get: + (a) the AIK certificate (from NV or by running the Privacy CA flow ourselves), and + (b) a raw TPM2_Quote blob (from `tpm2_quote` directly or the `pcrlist.dat` file), + then we could verify the attestation without going through Alibaba's `/quote` endpoint. + **This is the key question for vaportpm-verify integration.** + +6. **Is `trustclient-opensource` actually open source?** Build path suggests it might be. + No public repo found yet. + +7. **What is the `dataCredentialBlob` format exactly?** + - bytes[0:4] = unknown (version? magic? AES mode indicator?) + - bytes[4:20] = 16-byte AES IV + - bytes[20:] = AES-CBC(?) encrypted PEM certificate + - Key = TPM2_ActivateCredential output (HMAC-derived secret) + +8. **What is the exact AIK key type?** The key handle `0x81010003` is in persistent storage. + `TpmPreGeneratedKey(handle, algorithm=1)` - what does algorithm=1 map to? (likely RSA 2048) + +## Decompilation Artifacts + +- `trustagent-hexrays` - Hex-Rays decompilation of `/usr/local/bin/trust-agent` +- `libtrust_network.so.1.0.0.bndb_pseudo_c.txt` - BinaryNinja pseudo-C export of network library (1.1M lines) +- `libtrust_tpm.so.1.0.0.bndb_pseudo_c.txt` - BinaryNinja pseudo-C export of TPM library (210K lines) + +### Key functions in `libtrust_network.so` BN export (line numbers): +- `308423` - `TpmHttpVisitor::register_inst` +- `308917` - `TpmHttpVisitor::aik_cert` (fully analyzed) +- `309509` - `TpmHttpVisitor::attestation` (fully analyzed) +- `301886` - `ali_trust_init_tpm_visitor` (endpoint construction) +- `305055` - `TpmPopVisitor::register_inst` +- `305738` - `TpmPopVisitor::aik_cert` +- `306585` - `TpmPopVisitor::attestation` + +### Key functions in `libtrust_tpm.so` BN export (line numbers): +- `96987` - `TpmAttestationImpl::generate_aik_cert` (**fully analyzed** - the core Privacy CA flow) +- `94901` - `TpmAttestationImpl::renew_aik_cert` +- `95121` - `TpmAttestationImpl::generate_quote` +- `94126` - `TpmAttestationImpl::attestation` (thin wrapper → network) +- `78153` - `TpmToolsOpsImpl::run` (tpm2-tools dispatch) +- `78218` - `TpmSslOpsImpl::init` (OpenSSL + tpm2-openssl provider) +- `78312` - `TpmSslOpsImpl::run` (OpenSSL-based TPM ops) +- `78795` - `TpmDeviceProxy::run` (command dispatcher) +- `96508` - `TpmAttestationImpl::cache_aik_certs` (NV cert caching) +- `95743` - `TpmAttestationImpl::capability` +- `72827` - `ali_trust_tpm_init_context` +- `68522` - `ali_trust_tpm_generate_aik_cert` (outer wrapper with expiry check) + +## Next Steps + +- [x] ~~Decompile `libtrust_tpm.so` to understand the ActivateCredential flow~~ **DONE** - full flow documented +- [ ] Look at `TpmPopVisitor::aik_cert` to see if POP path has additional fields/steps +- [ ] Check if `ali_trust_generate_plat_cert` or `ali_trust_generate_app_cert` produce portable certs +- [ ] Search for the `trustclient-opensource` repo +- [ ] **Spin up an Alibaba Cloud ECS instance** to: + - Capture `/aikcert/produce` and `/quote` traffic + - Extract the AIK cert from NV (via `tpm2_nvread`) + - Determine the AIK cert CA chain + - Test if we can run `tpm2_quote` directly with the AIK key at `0x81010003` +- [ ] Determine if we can replicate the Privacy CA flow from Rust (for vaportpm-verify) +- [ ] Analyze whether the AIK cert + raw TPM2_Quote is sufficient for offline verification + +## References + +- [Keylime PR #1448](https://github.com/keylime/keylime/pull/1448) - Added Aliyun EK cert to keylime cert store +- [Alibaba Cloud Remote Attestation](https://www.alibabacloud.com/help/en/ecs/user-guide/remote-attestation-service) +- [Alibaba Cloud Trusted Computing](https://www.alibabacloud.com/help/en/ecs/user-guide/overview-of-trusted-computing-capabilities) +- [EAT Profile (TDX only)](https://www.alibabacloud.com/help/en/ecs/user-guide/eat-profile) +- [Create trusted instance (RAM policy with yundun-systrust actions)](https://www.alibabacloud.com/help/en/ecs/user-guide/create-a-security-enhanced-instance) diff --git a/experiments/alibaba/alibaba-trust-us-east-1.sh b/experiments/alibaba/alibaba-trust-us-east-1.sh new file mode 100644 index 0000000..9ce50cd --- /dev/null +++ b/experiments/alibaba/alibaba-trust-us-east-1.sh @@ -0,0 +1,144 @@ +#!/bin/sh +CURPATH=`pwd` +TOKEN=`curl -s -X PUT -H "X-aliyun-ecs-metadata-token-ttl-seconds: 120" "http://100.100.100.200/latest/api/token"` +REGION_ID=`curl -s --retry 1 --max-time 3 -H "X-aliyun-ecs-metadata-token: $token" http://100.100.100.200/latest/meta-data/region-id` +PROCESSOR=`uname -m` +VERSION="" +TRUSTAGENT_UPDATE_SITE1=http://trustclient-${REGION_ID}.oss-${REGION_ID}-internal.aliyuncs.com +TRUSTAGENT_UPDATE_SITE2=http://trustclient-${REGION_ID}.oss-${REGION_ID}.aliyuncs.com +TRUSTAGENT_UPDATE_SITE3=http://t-trustclient-${REGION_ID}.oss-${REGION_ID}-internal.aliyuncs.com + +get_last_version() +{ + echo "get last version from 1" + HTTP_CODE=`curl -IsL -w "%{http_code}\n" --retry 1 --max-time 3 "${TRUSTAGENT_UPDATE_SITE1}""$1" -o /dev/null` + if [ ${HTTP_CODE} -eq 200 ]; then + VERSION=`curl -s --retry 1 --max-time 3 "${TRUSTAGENT_UPDATE_SITE1}""$1"` + return 1 + fi + echo "get last version from 2" + HTTP_CODE=`curl -IsL -w "%{http_code}\n" --retry 1 --max-time 3 "${TRUSTAGENT_UPDATE_SITE2}""$1" -o /dev/null` + if [ ${HTTP_CODE} -eq 200 ]; then + VERSION=`curl -s --retry 1 --max-time 3 "${TRUSTAGENT_UPDATE_SITE2}""$1"` + return 2 + fi + echo "get last version from 3" + HTTP_CODE=`curl -IsL -w "%{http_code}\n" --retry 1 --max-time 3 "${TRUSTAGENT_UPDATE_SITE2}""$1" -o /dev/null` + if [ ${HTTP_CODE} -eq 200 ]; then + VERSION=`curl -s --retry 1 --max-time 3 "${TRUSTAGENT_UPDATE_SITE3}""$1"` + return 3 + fi + echo "get last version error" 1>&2 + exit 1 +} + +download_file() +{ + echo "download from 1" + wget -q -t 1 -T 5 "${TRUSTAGENT_UPDATE_SITE1}""$1" -O "$2" + if [ $? -eq 0 ]; then + return 1 + fi + echo "download from 2" + wget -q -t 1 -T 5 "${TRUSTAGENT_UPDATE_SITE2}""$1" -O "$2" + if [ $? -eq 0 ]; then + return 2 + fi + echo "download from 3" + wget -q -t 1 -T 5 "${TRUSTAGENT_UPDATE_SITE3}""$1" -O "$2" + if [ $? -eq 0 ]; then + return 3 + fi + rm -rf "$2" + echo "download file error" 1>&2 + exit 1 +} + +install_agent_centos() +{ + RPM_NAME="t-trustclient.bin.rpm" + RPM_MD5="t-trustclient.bin.rpm.md5" + + echo "downloading package version..." + get_last_version "/version/${PROCESSOR}/last" + echo "downloading package install..." + download_file "/download/linux/centos/${PROCESSOR}/${VERSION}/t-trustclient-${VERSION}-${PROCESSOR}.rpm" "${RPM_NAME}" + echo "downloading package checksum..." + download_file "/download/linux/centos/${PROCESSOR}/${VERSION}/t-trustclient-${VERSION}-${PROCESSOR}.rpm.md5" "${RPM_MD5}" + + echo "checking package file..." + md5_check=`md5sum "${RPM_NAME}" | awk '{print $1}' ` + md5_server=`head -1 "${RPM_MD5}" | awk '{print $1}'` + if [ "$md5_check"x = "$md5_server"x ] + then + echo "check package success" + + cd ${CURPATH} + chmod +x "${RPM_NAME}" + yum install -y "${RPM_NAME}" + if [ $? -eq 0 ]; then + echo "start trust agent..." + systemctl enable t-trustclient.service &>/dev/null + systemctl start t-trustclient.service &>/dev/null + if [ $? -eq 0 ]; then + echo "TrustAgent OK." + fi + fi + else + echo "checksum error"; + exit 1 + fi + + rm -f "${RPM_MD5}" + rm -f "${RPM_NAME}" +} + +install_agent_ubuntu() +{ + DEB_NAME="t-trustclient.bin.deb" + DEB_MD5="t-trustclient.bin.deb.md5" + + echo "downloading package version..." + get_last_version "/version/${PROCESSOR}/last" + echo "downloading package install..." + download_file "/download/linux/ubuntu/${PROCESSOR}/${VERSION}/t-trustclient-${VERSION}-${PROCESSOR}.deb" "${DEB_NAME}" + echo "downloading package checksum..." + download_file "/download/linux/ubuntu/${PROCESSOR}/${VERSION}/t-trustclient-${VERSION}-${PROCESSOR}.deb.md5" "${DEB_MD5}" + + echo "checking package file..." + md5_check=`md5sum "${DEB_NAME}" | awk '{print $1}' ` + md5_server=`head -1 "${DEB_MD5}" | awk '{print $1}'` + if [ "$md5_check"x = "$md5_server"x ] + then + echo "check package success" + + cd ${CURPATH} + chmod +x "${DEB_NAME}" + dpkg -i "${DEB_NAME}" + if [ $? -eq 0 ]; then + echo "start trust agent..." + systemctl enable t-trustclient.service &>/dev/null + systemctl start t-trustclient.service &>/dev/null + if [ $? -eq 0 ]; then + echo "TrustAgent OK." + fi + fi + else + echo "checksum error"; + exit 1 + fi + + rm -f "${DEB_MD5}" + rm -f "${DEB_NAME}" +} + +if lsb_release -d | grep -q -e "Ubuntu" -e "Debian"; then + install_agent_ubuntu +elif lsb_release -d | grep -q -e "Alibaba Cloud Linux" -e "CentOS" -e "Anolis"; then + install_agent_centos +else + echo "Unsupported Image!!!" + exit 1 +fi + +exit 0 diff --git a/experiments/alibaba/aliyun-ekmf-ca.crt b/experiments/alibaba/aliyun-ekmf-ca.crt new file mode 100644 index 0000000..37f9e6d --- /dev/null +++ b/experiments/alibaba/aliyun-ekmf-ca.crt @@ -0,0 +1,93 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=CN, O=Aliyun, OU=Aliyun TPM Root CA, CN=Aliyun TPM Root CA + Validity + Not Before: Sep 16 05:48:24 2021 GMT + Not After : Dec 31 23:59:59 2030 GMT + Subject: C=CN, O=Aliyun, OU=Aliyun TPM Endorsement Key Manufacture CA, CN=Aliyun TPM EKMF CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e5:59:24:2b:c3:ac:32:47:71:76:11:bf:d3:c5: + c3:05:13:07:81:a8:3a:4b:9a:c3:b4:7f:79:a9:bc: + 57:c0:4e:03:88:eb:df:50:02:14:89:9f:b9:d4:a7: + bc:f6:34:2f:69:05:f4:1b:21:f4:71:cd:f0:5e:0b: + 0a:4e:bb:10:14:cd:17:46:8e:3f:26:3d:a9:80:cc: + c9:4a:a5:4e:82:10:cf:08:4d:82:9b:5a:a0:b0:e4: + be:62:a0:56:37:d0:cd:6d:35:85:97:94:e1:6b:ff: + 9f:ee:67:bc:d1:fc:f9:70:e7:53:bd:80:cb:ec:ad: + 86:c7:fd:a2:1a:b5:d8:3f:2e:ed:bc:1b:ec:d6:98: + 90:73:39:1f:fc:d5:9b:7f:29:e9:c0:d2:b2:83:bb: + b0:ca:25:dd:dd:df:5e:ff:45:7e:d1:bf:7e:93:af: + 2d:75:d1:87:f0:7d:f4:b9:f7:46:bf:f4:e4:74:32: + 9a:0f:9a:0d:dc:43:a2:43:6c:9b:0d:58:1a:3c:6f: + 38:62:67:9a:f9:bc:2a:47:f6:03:b2:8b:48:41:25: + 39:85:57:c6:a5:84:4a:0d:b4:1d:19:e2:24:aa:6e: + 8f:6a:95:06:7d:60:4b:4e:cc:bf:6e:74:52:93:57: + 3a:b9:14:0e:85:54:35:2c:75:51:a5:44:7d:fe:21: + e2:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + CA Issuers - URI:https://aliyun-tpm-ca.oss-cn-beijing.aliyuncs.com/pki001/root-ca.crt + + X509v3 CRL Distribution Points: + + Full Name: + URI:https://aliyun-tpm-ca.oss-cn-beijing.aliyuncs.com/pki001/root-ca.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 81:AA:9A:64:92:88:FF:07:07:07:50:9A:CF:97:4E:FF:66:59:50:C8 + X509v3 Authority Key Identifier: + keyid:58:33:7A:9C:D0:E8:C3:61:21:67:43:91:3E:FC:21:7D:63:81:9B:1D + + Signature Algorithm: sha384WithRSAEncryption + 9e:03:04:94:17:88:9c:8f:23:81:9a:95:c3:21:2d:9e:6e:6c: + e3:18:08:7c:2d:aa:2c:dd:87:1d:0a:30:a9:7f:1f:76:83:37: + a8:b6:d4:8e:d9:68:b8:e6:53:45:e6:5b:41:d1:35:34:11:21: + 04:95:13:b7:23:06:e2:e8:4f:18:22:49:cc:aa:e0:b9:9c:ed: + c6:72:93:c7:07:ae:bb:3b:93:19:d4:b8:66:bf:1d:03:82:cd: + e3:ec:e0:0a:ba:2b:a7:77:b0:fa:11:1b:84:e6:ed:08:0b:32: + dc:be:4a:70:d9:b7:39:62:16:e4:b7:52:5c:2a:94:d8:2a:fe: + 55:f4:c7:62:66:fa:54:67:2c:7b:8f:70:d5:12:33:97:ae:cc: + ab:87:69:7d:66:4e:82:1b:e0:e9:4f:6d:a4:52:1e:06:e9:83: + 6e:a1:e0:5f:24:09:d6:37:60:0c:28:ec:cd:95:b0:6a:06:60: + 5b:d2:0e:c9:2c:34:e1:4d:7c:1d:8c:ec:61:ce:e1:36:d7:90: + c0:44:b4:52:80:89:77:31:36:7d:73:dd:af:44:cc:97:81:5b: + 07:ae:7f:f4:df:d8:b6:2f:1d:f3:65:de:f5:2f:c0:2a:26:de: + 04:b9:f9:f3:ef:c4:97:37:67:b6:fc:f5:7b:e2:ca:fd:5c:82: + af:b1:50:1a +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIBAjANBgkqhkiG9w0BAQwFADBYMQswCQYDVQQGEwJDTjEP +MA0GA1UECgwGQWxpeXVuMRswGQYDVQQLDBJBbGl5dW4gVFBNIFJvb3QgQ0ExGzAZ +BgNVBAMMEkFsaXl1biBUUE0gUm9vdCBDQTAgFw0yMTA5MTYwNTQ4MjRaGA8yMDMw +MTIzMTIzNTk1OVowbzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkFsaXl1bjEyMDAG +A1UECwwpQWxpeXVuIFRQTSBFbmRvcnNlbWVudCBLZXkgTWFudWZhY3R1cmUgQ0Ex +GzAZBgNVBAMMEkFsaXl1biBUUE0gRUtNRiBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAOVZJCvDrDJHcXYRv9PFwwUTB4GoOkuaw7R/eam8V8BOA4jr +31ACFImfudSnvPY0L2kF9Bsh9HHN8F4LCk67EBTNF0aOPyY9qYDMyUqlToIQzwhN +gptaoLDkvmKgVjfQzW01hZeU4Wv/n+5nvNH8+XDnU72Ay+ythsf9ohq12D8u7bwb +7NaYkHM5H/zVm38p6cDSsoO7sMol3d3fXv9FftG/fpOvLXXRh/B99Ln3Rr/05HQy +mg+aDdxDokNsmw1YGjxvOGJnmvm8Kkf2A7KLSEElOYVXxqWESg20HRniJKpuj2qV +Bn1gS07Mv250UpNXOrkUDoVUNSx1UaVEff4h4ncCAwEAAaOCAR4wggEaMGAGCCsG +AQUFBwEBBFQwUjBQBggrBgEFBQcwAoZEaHR0cHM6Ly9hbGl5dW4tdHBtLWNhLm9z +cy1jbi1iZWlqaW5nLmFsaXl1bmNzLmNvbS9wa2kwMDEvcm9vdC1jYS5jcnQwVQYD +VR0fBE4wTDBKoEigRoZEaHR0cHM6Ly9hbGl5dW4tdHBtLWNhLm9zcy1jbi1iZWlq +aW5nLmFsaXl1bmNzLmNvbS9wa2kwMDEvcm9vdC1jYS5jcmwwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIGqmmSSiP8HBwdQms+XTv9m +WVDIMB8GA1UdIwQYMBaAFFgzepzQ6MNhIWdDkT78IX1jgZsdMA0GCSqGSIb3DQEB +DAUAA4IBAQCeAwSUF4icjyOBmpXDIS2ebmzjGAh8Laos3YcdCjCpfx92gzeottSO +2Wi45lNF5ltB0TU0ESEElRO3Iwbi6E8YIknMquC5nO3GcpPHB667O5MZ1Lhmvx0D +gs3j7OAKuiund7D6ERuE5u0ICzLcvkpw2bc5Yhbkt1JcKpTYKv5V9MdiZvpUZyx7 +j3DVEjOXrsyrh2l9Zk6CG+DpT22kUh4G6YNuoeBfJAnWN2AMKOzNlbBqBmBb0g7J +LDThTXwdjOxhzuE215DARLRSgIl3MTZ9c92vRMyXgVsHrn/039i2Lx3zZd71L8Aq +Jt4Eufnz78SXN2e2/PV74sr9XIKvsVAa +-----END CERTIFICATE----- diff --git a/experiments/alibaba/aliyun-root-ca.crt b/experiments/alibaba/aliyun-root-ca.crt new file mode 100644 index 0000000..2e7d383 --- /dev/null +++ b/experiments/alibaba/aliyun-root-ca.crt @@ -0,0 +1,81 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=CN, O=Aliyun, OU=Aliyun TPM Root CA, CN=Aliyun TPM Root CA + Validity + Not Before: Sep 16 05:46:41 2021 GMT + Not After : Dec 31 23:59:59 2030 GMT + Subject: C=CN, O=Aliyun, OU=Aliyun TPM Root CA, CN=Aliyun TPM Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cb:57:f6:52:97:43:65:2e:64:c3:a7:49:df:79: + 05:c2:9b:69:a9:ef:1c:49:90:89:79:64:92:6d:1f: + cc:a9:91:35:3e:7a:cf:68:e0:a1:2f:dd:5b:a8:d5: + 26:0e:53:19:65:40:b9:51:3d:d2:20:9d:24:d0:1b: + e3:23:c2:9c:85:ce:5e:d4:68:e9:13:2d:de:80:10: + 28:63:54:8d:2c:8d:4f:1f:e0:e8:d6:55:8f:6c:f4: + f6:47:aa:54:05:a6:a8:05:ac:31:62:c8:dc:6f:8f: + 3d:18:79:75:7f:8d:01:d7:f3:ed:18:7c:1e:12:85: + 52:6c:be:47:16:b6:6d:17:cf:c6:1d:eb:ab:c0:c2: + 25:43:7a:7d:4c:e7:d1:0e:79:46:36:76:5e:c2:2b: + 35:81:55:bd:ac:53:ac:81:ad:db:90:f6:93:b4:70: + 36:45:d3:9c:1d:1a:5b:67:7f:db:0a:c2:c1:fe:0f: + d7:55:5e:61:1c:cd:7b:02:23:66:ca:f8:65:b6:4a: + 3c:00:a1:dc:9c:f7:cc:c6:48:69:8b:8e:6c:be:a0: + 8c:59:e6:17:8d:e8:9f:4b:18:42:3d:d3:d8:7f:bf: + a2:37:31:3e:bb:dd:56:b2:7e:26:5a:20:1b:af:45: + a2:87:6a:d9:a9:7d:ab:1a:a4:29:bb:a9:f6:20:5a: + f9:53 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 58:33:7A:9C:D0:E8:C3:61:21:67:43:91:3E:FC:21:7D:63:81:9B:1D + X509v3 Authority Key Identifier: + keyid:58:33:7A:9C:D0:E8:C3:61:21:67:43:91:3E:FC:21:7D:63:81:9B:1D + + Signature Algorithm: sha384WithRSAEncryption + b4:ce:bd:c6:b5:8d:06:85:f0:46:45:98:20:5e:ef:0a:8f:7f: + d9:ea:e3:ce:aa:fa:48:27:e2:96:7d:b9:c3:ef:19:34:f5:f0: + 3a:30:33:9e:bc:e5:3f:17:59:58:9f:3c:5f:45:a9:8a:b1:61: + 27:72:97:dc:91:01:be:36:48:a7:5d:1c:a6:ae:83:c3:dc:45: + 82:c2:f3:30:80:25:46:e3:8f:df:b6:8b:20:24:69:ec:30:e5: + d5:62:08:2c:f0:e2:42:cb:76:6c:ec:ee:66:bc:16:5d:a6:d1: + 67:7c:c1:3b:e7:be:73:09:b4:05:99:c3:49:11:c8:6d:17:9d: + b1:7d:5e:bd:c5:08:4a:95:ba:59:72:d7:b9:b3:b3:58:f5:2d: + a1:7f:6a:29:14:bc:d3:8b:33:5c:8e:6f:f5:f2:ba:97:8f:ad: + 6c:2a:91:25:70:f9:4a:8f:7e:51:8c:0a:8f:c1:fe:41:da:a5: + e1:fd:2d:8b:de:5e:00:74:6d:a3:7c:b3:38:d6:30:d6:90:cf: + b9:7d:08:a5:82:f3:cb:db:4d:62:b0:c7:96:0f:f6:a6:7e:1e: + 79:04:03:83:57:4d:b0:93:ca:71:74:75:76:ea:20:0a:9a:b9: + 9d:0e:0e:dd:4f:52:f3:ff:c0:13:3c:d8:ca:7a:5a:2f:d8:4e: + 98:41:a9:62 +-----BEGIN CERTIFICATE----- +MIIDkDCCAnigAwIBAgIBATANBgkqhkiG9w0BAQwFADBYMQswCQYDVQQGEwJDTjEP +MA0GA1UECgwGQWxpeXVuMRswGQYDVQQLDBJBbGl5dW4gVFBNIFJvb3QgQ0ExGzAZ +BgNVBAMMEkFsaXl1biBUUE0gUm9vdCBDQTAgFw0yMTA5MTYwNTQ2NDFaGA8yMDMw +MTIzMTIzNTk1OVowWDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkFsaXl1bjEbMBkG +A1UECwwSQWxpeXVuIFRQTSBSb290IENBMRswGQYDVQQDDBJBbGl5dW4gVFBNIFJv +b3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLV/ZSl0NlLmTD +p0nfeQXCm2mp7xxJkIl5ZJJtH8ypkTU+es9o4KEv3Vuo1SYOUxllQLlRPdIgnSTQ +G+MjwpyFzl7UaOkTLd6AEChjVI0sjU8f4OjWVY9s9PZHqlQFpqgFrDFiyNxvjz0Y +eXV/jQHX8+0YfB4ShVJsvkcWtm0Xz8Yd66vAwiVDen1M59EOeUY2dl7CKzWBVb2s +U6yBrduQ9pO0cDZF05wdGltnf9sKwsH+D9dVXmEczXsCI2bK+GW2SjwAodyc98zG +SGmLjmy+oIxZ5heN6J9LGEI909h/v6I3MT673VayfiZaIBuvRaKHatmpfasapCm7 +qfYgWvlTAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBRYM3qc0OjDYSFnQ5E+/CF9Y4GbHTAfBgNVHSMEGDAWgBRYM3qc +0OjDYSFnQ5E+/CF9Y4GbHTANBgkqhkiG9w0BAQwFAAOCAQEAtM69xrWNBoXwRkWY +IF7vCo9/2erjzqr6SCfiln25w+8ZNPXwOjAznrzlPxdZWJ88X0WpirFhJ3KX3JEB +vjZIp10cpq6Dw9xFgsLzMIAlRuOP37aLICRp7DDl1WIILPDiQst2bOzuZrwWXabR +Z3zBO+e+cwm0BZnDSRHIbRedsX1evcUISpW6WXLXubOzWPUtoX9qKRS804szXI5v +9fK6l4+tbCqRJXD5So9+UYwKj8H+Qdql4f0ti95eAHRto3yzONYw1pDPuX0IpYLz +y9tNYrDHlg/2pn4eeQQDg1dNsJPKcXR1duogCpq5nQ4O3U9S8//AEzzYynpaL9hO +mEGpYg== +-----END CERTIFICATE-----