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:
- merchant-terminal-attestation-investigation.md — full investigation
- softspace-play-integrity-whitelist.md — operational whitelist steps
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¶
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.cert → READY + attestation fail.
Align release builds:
- Compare:
./apps/terminal/scripts/verify-softspace-exchange-cert.sh ~/wl/sagio_app_final.cert /path/to.apk - If cert matches HSM pubkey in repo → ship via Play internal test, not raw CI APK.
- If cert is a standalone UAT key → put that keystore in
keystore.propertiesandSAGIO_KEYSTORE_*, thenassembleRelease.
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:
- Device
cotsIdis registered under that MUID in UAT portal. - Key injection completed for this app (
io.sagio.merchant). - 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¶
- Zip
~/wland share with SAGIO (all five files). - State how he installed the app: debug build, Diawi/CI release, or Play internal test.
- 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).