mirror of
https://github.com/block/buzz.git
synced 2026-11-07 18:01:06 +00:00
fix(push): verify App Attest proofs with a focused owned module
Signed-off-by: Tom Brow <tomb@block.xyz>
This commit is contained in:
81
docs/app-attest-compatibility.md
Normal file
81
docs/app-attest-compatibility.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# App Attest compatibility boundary
|
||||
|
||||
The push gateway verifies enrollment and assertions through a private
|
||||
[Buzz-owned module](../crates/buzz-push-gateway/src/app_attest.rs). Extended authenticators must
|
||||
remain compatible without weakening the checks that bind a request to an app,
|
||||
key, challenge, and increasing counter.
|
||||
|
||||
## Receiver policy
|
||||
|
||||
Enrollment requires the fixed authenticator prefix, AAGUID, credential ID, and a
|
||||
complete COSE P-256 key. The COSE key must match the leaf certificate key. Any
|
||||
remaining bytes form one complete extension map. Assertions require the fixed
|
||||
37-byte prefix and, when present, one complete extension map. Neither operation
|
||||
uses a total length or flags allowlist to recognize an Apple SDK version.
|
||||
|
||||
Every original authenticator byte participates in the certificate nonce or
|
||||
assertion signature. Verification does not truncate or re-encode that byte
|
||||
string. Assertion signatures and enrollment certificate nonces are checked
|
||||
before decoding the extension payload. Unknown extension identifiers and opaque
|
||||
optional property values do not authorize or reject a request by themselves.
|
||||
Malformed structure, ambiguous duplicate keys, and trailing data are rejected.
|
||||
|
||||
CBOR accepts well-formed definite/indefinite containers and strings, nonpreferred
|
||||
integer widths, and opaque tagged/simple values under bounded resource limits.
|
||||
Map-key equality follows the generic CBOR model, including compound keys;
|
||||
integers and floating-point values remain distinct. Schema-bearing maps require
|
||||
their specified text or COSE labels.
|
||||
|
||||
The gateway retains its configured Apple root and exact server-selected app and
|
||||
attestation environment. Certificate validation uses webpki; field extraction
|
||||
uses x509-parser. The nonce extension must have its complete canonical structure.
|
||||
The leaf key, credential ID, supplied key ID, zero enrollment counter, and app
|
||||
hash must agree. Assertions retain signature, app hash, challenge, and increasing
|
||||
counter checks. Existing atomic database updates remain the replay boundary.
|
||||
|
||||
The verifier consumes EKU OIDs without applying TLS purposes to App Attest and
|
||||
honors supplied digital-signature/key-cert-sign usage restrictions. It does not
|
||||
perform revocation checking or Apple's separate receipt risk assessment.
|
||||
|
||||
Version text and raw four-byte category values are bounded diagnostic
|
||||
observations only. Unsupported optional representations remain opaque. No
|
||||
version or category restriction is introduced.
|
||||
|
||||
## Capacity and tests
|
||||
|
||||
Parser limits are service policy: 64 KiB encoded input, 4096 decoded nodes,
|
||||
depth 32, and 64 KiB copied strings/bytes. Declared lengths do not drive
|
||||
preallocation. Gateway transport limits remain 16 KiB for enrollment and 1 KiB
|
||||
for assertions. Tests cover boundaries, oversized declared lengths, truncations,
|
||||
duplicate equivalence, and structurally invalid signed payloads.
|
||||
|
||||
Signed synthetic enrollment tests cover COSE parity/reordering, extension
|
||||
variation, certificate constraints, nonce integrity, wrong identity/key binding,
|
||||
and incomplete credentials. Gateway tests verify legacy and extended assertions,
|
||||
tamper rejection, wrong transcript/key/app, and replay rejection. The signed-certificate suite runs with the gateway unit tests. Fixture helpers
|
||||
are compiled only for tests, including in personal-development builds.
|
||||
|
||||
Physical-device validation used one probe identity on iOS 27.0.1:
|
||||
|
||||
| SDK | Enrollment authenticator | Assertion authenticator | Key relationship |
|
||||
| --- | ---: | ---: | --- |
|
||||
| 26.5 | 164 bytes | 37 bytes | Original probe key |
|
||||
| 27.1 | Previously enrolled | 102 bytes | Same original key |
|
||||
| 27.1 | 229 bytes | 102 bytes | Additional fresh probe key |
|
||||
|
||||
All three assertions and both enrollments pass the gateway verifier. Same-key
|
||||
counters increase; repeated counters and altered transcripts fail. Development
|
||||
enrollments fail under the production environment. These are local verifier
|
||||
results, not evidence of a deployed gateway or APNs delivery. Raw device captures
|
||||
stay outside the repository; optional ignored tests consume protected local
|
||||
inputs for repeatable validation.
|
||||
|
||||
## Source provenance
|
||||
|
||||
Adapted portions originate in [appattest 0.1.1](https://crates.io/crates/appattest/0.1.1),
|
||||
[upstream commit d1ffda7](https://github.com/PrismaPhonic/appattest/commit/d1ffda733f6e7f267aab79ae42b8ec7f60ceada1).
|
||||
The package SHA-256 is `5d0a66767aaf7d483c556386fb68ca2fba9347684d8bb17a4bd8b755851870f7`.
|
||||
Both upstream MIT notices are retained in the module's
|
||||
[LICENSE](../crates/buzz-push-gateway/src/app_attest/LICENSE).
|
||||
The gateway owns its verification policy and tracks Apple protocol and underlying
|
||||
cryptographic-library updates directly. There is no remaining appattest dependency.
|
||||
Reference in New Issue
Block a user