Skip to content

Soft Space Exchange Archive (Chris ~/wl)

Context: Chris Kwon shared the exact files from the original Soft Space onboarding / whitelist exchange (~/wl on his machine). This doc maps those files to our Cloud HSM material and explains what to verify when Settings READY but attestation still fails.

Soft Space email (UAT): Liew Zhi Ying confirmed Chris’s cert was verified, the app was whitelisted in UAT, and issued integrator accessKey / secretKey for the SDK. Those keys belong in apps/api/.env.local + Cloudflare (FASSTAP_ACCESS_KEY, FASSTAP_SECRET_KEY) — not in the Android APK. As of 2026-05-22, FASSTAP_SECRET_KEY on the worker was updated to match the email (it had previously differed).

Related:


Chris’s archive (~/wl)

From Chris’s terminal listing:

File Likely purpose Used by Soft Space for
sagio_application_id.txt Android package name Play Integrity package allowlist → expect io.sagio.merchant
sagio_pk.pem App signing public key (PEM) Confirms which key was registered; must match Cloud HSM / Play App Signing
sagio_app_final.cert App signing X.509 certificate Certificate SHA-256 whitelist for Play Integrity (primary artifact)
SAGIO_id_cert Sagio / integrator identity certificate Worldline onboarding identity (not the APK signing cert)
softspace-attestation.asc ASCII-armored file (often PGP) Soft Space signed acknowledgment or attestation record of what they registered

These are the right class of artifacts for Play Integrity allowlisting — unlike the Cloud HSM .dat file, which is for KMS/HSM compliance, not Soft Space.


Cloud HSM file in ~/Downloads (SAGIO side)

File Purpose
sagio-production-ring-sagio-app-signer-1-CAVIUM_V2_COMPRESSED-attestation.dat Google Cloud KMS HSM vendor attestation (gzip → Cavium TLV blob)

KMS resource verified (2026-05-22):

projects/sagio-484122/locations/australia-southeast1/keyRings/sagio-production-ring/cryptoKeys/sagio-app-signer/cryptoKeyVersions/1

Parsing results (~/Downloads/...attestation.dat)

Property Value
Format CAVIUM_V2_COMPRESSED (gzip, 1002 → 2528 bytes decompressed)
Contains X.509 / PEM cert? No (no BEGIN CERTIFICATE, no DER 30 82 sequences)
Label in blob app_key
Key ID field (128 hex = two SHA-256 digests) See below

Key ID verification (per Google KMS attest-key):

The second 32-byte digest in the attestation key ID must equal SHA-256 of the key version resource name:

RESOURCE_NAME="projects/sagio-484122/locations/australia-southeast1/keyRings/sagio-production-ring/cryptoKeys/sagio-app-signer/cryptoKeyVersions/1"
echo -n "$RESOURCE_NAME" | openssl dgst -sha256 -hex
# → f679bb1bba71cf6b2a16799b4121e5554ca8cbbfe6c41a6b838399803524ed72  ✓ matches attestation blob

Conclusion: The .dat file is authentic for sagio-app-signer version 1. It does not replace sagio_app_final.cert for Soft Space — different systems (HSM proof vs Play Integrity allowlist).

Public key for the same KMS version (in repo): apps/terminal/signing/sagio-app-signer.public.pem


How the two archives relate

flowchart TB
  subgraph gcp [Google Cloud HSM]
    KMS[sagio-app-signer v1]
    DAT[attestation.dat]
    PUB[sagio-app-signer.public.pem]
    KMS --> DAT
    KMS --> PUB
  end
  subgraph play [Google Play App Signing]
    PUB --> PLAY[Play re-signs store APKs]
    CERT[App signing X.509 cert]
    PLAY --> CERT
  end
  subgraph ss [Soft Space exchange - Chris ~/wl]
    PK[sagio_pk.pem]
    FINAL[sagio_app_final.cert]
    APPID[sagio_application_id.txt]
    SSASC[softspace-attestation.asc]
    FINAL --> WL[Play Integrity whitelist]
    APPID --> WL
  end
  CERT -.->|should match| FINAL
  PUB -.->|should match| PK
Question Where to check
Is HSM key the one we think? .dat resource ID hash ✓ (above)
Did Soft Space whitelist the right cert? sagio_app_final.cert SHA-256 vs Chris’s installed APK
Did Soft Space whitelist the right package? sagio_application_id.txt == io.sagio.merchant
Does Chris’s APK use that cert? apksigner verify --print-certs on his APK — if mismatch → attestation fails with READY

Verification checklist (when Chris shares ~/wl files)

Run from a machine that has the archive (or after Chris zips ~/wl to SAGIO):

1. Package name

cat sagio_application_id.txt
# Expected: io.sagio.merchant

2. Public key matches Cloud HSM / repo

diff <(openssl pkey -pubin -in sagio_pk.pem -pubout) \
     <(openssl pkey -pubin -in apps/terminal/signing/sagio-app-signer.public.pem -pubout)
# No output = match

3. Certificate fingerprint Soft Space registered

openssl x509 -in sagio_app_final.cert -noout -subject -issuer -fingerprint -sha256
keytool -printcert -file sagio_app_final.cert | rg SHA256

Save that SHA-256 — it is what Soft Space should have whitelisted for Play-delivered builds.

4. Compare to Chris’s installed APK (decisive)

adb shell pm path io.sagio.merchant
adb pull "$(adb shell pm path io.sagio.merchant | cut -d: -f2)" /tmp/chris-sagio.apk
apksigner verify --print-certs /tmp/chris-sagio.apk
# SHA-256 on APK MUST match sagio_app_final.cert (or debug/upload cert if different build channel)

5. Integrator cert (informational)

openssl x509 -in SAGIO_id_cert -noout -subject -issuer -dates 2>/dev/null || \
  openssl x509 -inform DER -in SAGIO_id_cert -noout -subject 2>/dev/null

6. Soft Space PGP artifact

file softspace-attestation.asc
gpg --verify softspace-attestation.asc 2>&1 | head -20
# Documents what Soft Space confirmed; not used by the Android SDK at runtime

PGP exchange vs how we build release APKs

Your suspicion is correct: Soft Space whitelisted whatever is in sagio_app_final.cert (and sagio_pk.pem). Play Integrity on the phone checks the APK signing cert, not the PGP file itself.

Artifact Role
sagio_app_final.cert Cert Soft Space whitelisted (SHA-256)
sagio_pk.pem Public key matching that cert
softspace-attestation.asc Soft Space’s signed record of the exchange — not used at runtime on device
CI / Diawi release APK Signed with SAGIO_KEYSTORE_* (Play upload key) unless you changed it
Debug APK Signed with debug keystore

If upload/debug cert ≠ sagio_app_final.certREADY + attestation fail.

Align release builds:

  1. Compare: ./apps/terminal/scripts/verify-softspace-exchange-cert.sh ~/wl/sagio_app_final.cert /path/to.apk
  2. If cert matches HSM pubkey in repo → ship via Play internal test, not raw CI APK.
  3. If cert is a standalone UAT key → put that keystore in keystore.properties and SAGIO_KEYSTORE_*, then assembleRelease.

Fix: “unlock fail” after attestation passes

Attestation = signing cert OK. Unlock = Soft Space login + key load on mpos-uat.fasspay.com:9002 using portal MUID (uniqueId) + device registration.

Sagio-side (do first)

Step Action
1 Confirm prod API is fine — terminal uses api.sagio.io with FASSTAP_ENVIRONMENT=UAT (not a bug).
2 Set Chris’s portal MUID on his merchant row (not only global automation tester):
cd apps/api && bun run set-merchant-fasstap-ids -- --email chriskwon0@gmail.com --unique-id <MUID> --developer-id <SSO>
3 Rebuild/install APK with SDK session reset on Refresh (see FasstapManager.resetSession() on branch).
4 On device: Settings → Refresh SDK Credentials → confirm Portal MUID line → retry Card.
5 If still failing: Clear All Settings or reinstall → open app (re-auth) → Refresh → Charge.

Soft Space–side (email Liew with)

Item Value to send
Package io.sagio.merchant
Portal MUID From Settings Portal MUID or fasstap_unique_id
Company SSO FASSTAP_DEVELOPER_ID / yjOItT3r3MKqRZE (if unchanged)
Device ID Logcat cotsId= after SDK initialized
Error Exact statusMessage (e.g. unlock fail) + statusCode from logcat

Ask Soft Space to confirm:

  1. Device cotsId is registered under that MUID in UAT portal.
  2. Key injection completed for this app (io.sagio.merchant).
  3. Mobile user / company status is Active (not suspended — codes 3011, 5010, 3032).

Logcat

adb logcat -c
# one failed charge
adb logcat -d | rg -i "FasstapManager|RefreshToken|unlock|statusMessage|statusCode|cotsId"

Why READY + attestation fail can still happen with this archive

Scenario What happened
Soft Space whitelisted sagio_app_final.cert (Play/HSM) Correct for Play Store installs
Chris tests debug or Diawi release APK APK signed with different cert → attestation fails
sagio_pk.pem matches HSM but cert on device differs Same as above — whitelist is per cert, not per public key alone
Package typo in sagio_application_id.txt Play Integrity package check fails
Whitelist never applied on Soft Space UAT READY (Sagio API) OK; SDK attestation still rejected

Action: Run §4 (APK vs sagio_app_final.cert). That single comparison usually explains the symptom.


What to request from Chris

  1. Zip ~/wl and share with SAGIO (all five files).
  2. State how he installed the app: debug build, Diawi/CI release, or Play internal test.
  3. Optional: one logcat snippet from failed charge (FasstapManager, statusMessage, integrity).

Repo copies (SAGIO)

Artifact Location
HSM public key apps/terminal/signing/sagio-app-signer.public.pem
Fingerprint script apps/terminal/scripts/print-softspace-fingerprints.sh
Chris archive mapping This file

Pending: Add sagio_app_final.cert under apps/terminal/signing/ after Chris shares it (public cert only — safe to commit).