Skip to content

Provider trust_level=hardware set even when MDA→SE-key binding fails (43% of live providers) #147

@amiller

Description

@amiller

Summary

The coordinator's verifyAppleDeviceAttestation (coordinator/internal/api/provider.go:1411-1497) computes SEKeyBound = (sha256(SE_pubkey_b64) == leaf_cert.OID(1.2.840.113635.100.8.11.1)) to verify that the SE pubkey signing the AttestationBlob is the same one Apple's MDA cert chain vouches for. However, MDAVerified=true and trust_level=hardware are set regardless of SEKeyBound. SEKeyBound is also not exposed in the public /v1/providers/attestation feed, so external auditors cannot detect the gap themselves.

In the live network on 2026-05-10, 13 of 30 (43%) hardware-trust providers have SEKeyBound=false — Apple's cert vouches for a real Apple device, but the SE pubkey those providers use today is not the one Apple bound. Routing then sends prompts to providers whose strongest claim is "the same coordinator that registered me asserts this is the right SE pubkey now."

Reproduce

curl -sS https://api.darkbloom.dev/v1/providers/attestation > feed.json
python3 - <<'PY'
import json, base64, hashlib
from cryptography import x509
d = json.load(open('feed.json'))
holds, fails = 0, 0
for p in d['providers']:
    if not p.get('mda_verified'): continue
    chain = p.get('mda_cert_chain_b64') or []
    if not chain: continue
    leaf = x509.load_der_x509_certificate(base64.b64decode(chain[0]))
    ext = next((e for e in leaf.extensions
                if e.oid.dotted_string == '1.2.840.113635.100.8.11.1'), None)
    if not ext: continue
    raw = bytes(ext.value.value if hasattr(ext.value,'value') else ext.value)
    if len(raw) >= 2 and raw[0] == 0x04 and raw[1] == len(raw)-2: raw = raw[2:]
    expected = hashlib.sha256(p['se_public_key'].encode('ascii')).digest()
    if raw == expected: holds += 1
    else: fails += 1
print(f'holds {holds}, fails {fails}')
PY
# 2026-05-10: holds 17, fails 13

A working provider (binding holds, f99b7905, M2 Max, serial WRPWFW61H9):

SE pubkey      qKxKds4zZk81flmOxcOmQVYSL0xkeg88tLBfXd7ghhJ/QYjW5ZKBAzASJ0TPwseWv38jW61NESGDtGsJqdzJ9Q==
sha256(b64)    984a169f28cd03dd50df4772724174bf3573486b20384918fe44eca467d86a98
OID 100.8.11.1 984a169f28cd03dd50df4772724174bf3573486b20384918fe44eca467d86a98 ✓

A failing provider (46a8fd75, M4 Max, serial HH0K6TJY0J, leaf cert valid 2026-04-24 → 2026-07-24):

SE pubkey      RUw/GIa+bga22J5hBA2HksqWx1XdqN0apPAyIQZwXNkihmylxRMoBo0eLkA213MOOye8+0RlH+f1gBooTKxD6A==
sha256(b64)    d7337511c8acde7ac8e072e3ffaf5f3756d1d36e11b0c6230ed652148a8d87b6
OID 100.8.11.1 50b295bd88cf6977d95e000845d9dd8250d64e9ce08371f80e33f4ac14ff3d26 ✗

Cert ages don't explain the split (matches median 7d, fails median 8d, both well within the 90-day window). Most likely the SE key was rotated (re-install / refresh) between MDA requests; the existing leaf binds an earlier SE key.

Code sites

  • coordinator/internal/api/provider.go:1487-1497MDAVerified=true and SEKeyBound=... set independently
  • coordinator/internal/registry/scheduler.go:370,650 — routing only checks trust_level >= MinTrustLevel, not SEKeyBound
  • coordinator/internal/api/provider.go:1540-1626/v1/providers/attestation response struct does not include SEKeyBound
  • coordinator/internal/api/me_handlers.go:64,576SEKeyBound IS exposed in the authenticated /me endpoint, just not the public feed

Paper concordance

Findable from the paper alone as an inconsistency between architectural claim and operational definition:

  • §17 conclusion (lines 985-988) lists "MDA nonce-based SE key binding" as one of five attestation layers that "provides defense-in-depth where each layer independently verifies properties that the others cannot."
  • Definition 5 "Verified Provider" (§5.4 lines 358-374) item 5 only requires "Apple MDA certificate chain is valid and serial number matches self-reported attestation" — no binding requirement.

So the paper's conclusion claims a property that its operational verification definition doesn't enforce.

Suggested fix (any of these closes the gap)

  1. Recommended: require SEKeyBound==true for trust_level=hardware. Demote to self_signed otherwise. This silently downgrades 13 providers today until they re-attest, which is the right answer for the "hardware trust" claim to mean what it says, and aligns Definition 5 with the §17 architectural claim.
  2. Re-issue MDA whenever the SE pubkey changes during a registration cycle. Trigger a fresh verifyAppleDeviceAttestation from provider.go whenever attestResult.PublicKey differs from the value stored at last MDA time.
  3. At minimum: publish se_key_bound in the /v1/providers/attestation response so external verifiers can detect the gap themselves. This is a one-field change in the response struct at provider.go:1540-1626.

(1) is the right fix; (3) is the minimum to make the public feed honest about what trust_level=hardware actually proves today.


Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions