@motebit/crypto-android-keystore 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +206 -0
- package/NOTICE +19 -0
- package/README.md +60 -0
- package/dist/asn1.d.ts +82 -0
- package/dist/asn1.d.ts.map +1 -0
- package/dist/asn1.js +257 -0
- package/dist/asn1.js.map +1 -0
- package/dist/google-roots.d.ts +89 -0
- package/dist/google-roots.d.ts.map +1 -0
- package/dist/google-roots.js +136 -0
- package/dist/google-roots.js.map +1 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/verify.d.ts +179 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +423 -0
- package/dist/verify.js.map +1 -0
- package/package.json +80 -0
package/dist/verify.js
ADDED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Android Hardware-Backed Keystore Attestation verifier — the core
|
|
3
|
+
* judgment function this package exports.
|
|
4
|
+
*
|
|
5
|
+
* Flow (matches Google's published verification recipe at
|
|
6
|
+
* https://source.android.com/docs/security/features/keystore/attestation,
|
|
7
|
+
* plus the motebit-specific identity-key binding step):
|
|
8
|
+
*
|
|
9
|
+
* 1. Split the receipt into the leaf cert plus the rest of the chain
|
|
10
|
+
* (`{leafCertB64}.{intermediatesJoinedB64}` — comma-joined leaf-
|
|
11
|
+
* proximal-first base64url DER blobs in the second segment).
|
|
12
|
+
* 2. Parse the chain as X.509 certificates. Walk the chain leaf →
|
|
13
|
+
* intermediates → terminal anchor with `@peculiar/x509`'s
|
|
14
|
+
* `X509ChainBuilder`. Every non-leaf must carry
|
|
15
|
+
* `basicConstraints.cA === true`. Every signature must verify
|
|
16
|
+
* under its issuer's public key. Every cert must be within its
|
|
17
|
+
* validity window. The terminal cert's DER must equal one of the
|
|
18
|
+
* pinned Google attestation roots.
|
|
19
|
+
* 3. Read the Android Key Attestation extension (OID
|
|
20
|
+
* `1.3.6.1.4.1.11129.2.1.17`) from the LEAF cert only. The AOSP
|
|
21
|
+
* spec is explicit that later occurrences of this extension up
|
|
22
|
+
* the chain MUST be ignored — only the leaf's copy carries
|
|
23
|
+
* trustworthy data, because only the leaf is signed by the
|
|
24
|
+
* device's secure-hardware key.
|
|
25
|
+
* 4. Constrain the parsed `KeyDescription`:
|
|
26
|
+
* - `attestationSecurityLevel ≥ TRUSTED_ENVIRONMENT` (rejects
|
|
27
|
+
* software-only fallback, which is structurally not
|
|
28
|
+
* third-party meaningful)
|
|
29
|
+
* - `attestationVersion ≥ 3` (rejects pre-Android-7 / Keymaster
|
|
30
|
+
* v2; current production is 4 / Keymaster 4 through 400 /
|
|
31
|
+
* KeyMint 4.0)
|
|
32
|
+
* - `hardwareEnforced.rootOfTrust.verifiedBootState` is in the
|
|
33
|
+
* caller's allowlist (default: VERIFIED only)
|
|
34
|
+
* - `hardwareEnforced.attestationApplicationId` byte-equals
|
|
35
|
+
* the caller's expected package binding
|
|
36
|
+
* - leaf's serial number is not in the caller-supplied
|
|
37
|
+
* revocation snapshot
|
|
38
|
+
* 5. Cryptographically bind the leaf's `attestationChallenge` field
|
|
39
|
+
* to the motebit Ed25519 identity: re-derive
|
|
40
|
+
* `SHA-256(canonicalJson({ attested_at, device_id,
|
|
41
|
+
* identity_public_key, motebit_id, platform: "android_keystore",
|
|
42
|
+
* version: "1" }))` and byte-compare against the transmitted
|
|
43
|
+
* challenge. A malicious client that substitutes any other body
|
|
44
|
+
* fails here.
|
|
45
|
+
*
|
|
46
|
+
* Pure. No network. No filesystem. Deterministic given `now()` and
|
|
47
|
+
* the caller-supplied revocation snapshot.
|
|
48
|
+
*/
|
|
49
|
+
import * as x509 from "@peculiar/x509";
|
|
50
|
+
import { ANDROID_KEY_ATTESTATION_OID, DEFAULT_ANDROID_KEYSTORE_TRUST_ANCHORS, } from "./google-roots.js";
|
|
51
|
+
import { parseKeyDescription, SECURITY_LEVEL_TRUSTED_ENVIRONMENT, VERIFIED_BOOT_STATE_VERIFIED, } from "./asn1.js";
|
|
52
|
+
/** Empty revocation snapshot — every leaf passes the revocation check. */
|
|
53
|
+
export const EMPTY_REVOCATION_SNAPSHOT = { entries: {} };
|
|
54
|
+
/**
|
|
55
|
+
* Android Hardware-Backed Keystore Attestation verifier.
|
|
56
|
+
*
|
|
57
|
+
* `claim.attestation_receipt` is the cert chain encoded as
|
|
58
|
+
* `{leafCertB64}.{intermediatesJoinedB64}` — leaf-first DER chain
|
|
59
|
+
* matching the wire format the Kotlin `expo-android-keystore` mint
|
|
60
|
+
* path emits. The intermediates segment is a comma-joined list of
|
|
61
|
+
* base64url-encoded DERs in leaf-proximal-first order; an empty
|
|
62
|
+
* second segment means the leaf chains directly to a pinned root.
|
|
63
|
+
*/
|
|
64
|
+
export async function verifyAndroidKeystoreAttestation(claim, opts) {
|
|
65
|
+
const errors = [];
|
|
66
|
+
let cert_chain_valid = false;
|
|
67
|
+
let attestation_extension_valid = false;
|
|
68
|
+
let identity_bound = false;
|
|
69
|
+
let attestation_security_level = null;
|
|
70
|
+
let verified_boot_state = null;
|
|
71
|
+
if (!claim.attestation_receipt) {
|
|
72
|
+
errors.push({ message: "android_keystore claim missing `attestation_receipt`" });
|
|
73
|
+
return finalize();
|
|
74
|
+
}
|
|
75
|
+
const parts = claim.attestation_receipt.split(".");
|
|
76
|
+
if (parts.length !== 2) {
|
|
77
|
+
errors.push({
|
|
78
|
+
message: `attestation_receipt must be 2 base64url parts (leafCert.intermediates); got ${parts.length}`,
|
|
79
|
+
});
|
|
80
|
+
return finalize();
|
|
81
|
+
}
|
|
82
|
+
const [leafB64, intermediatesB64] = parts;
|
|
83
|
+
let leafBytes;
|
|
84
|
+
let intermediatesBytes;
|
|
85
|
+
try {
|
|
86
|
+
leafBytes = fromBase64Url(leafB64);
|
|
87
|
+
intermediatesBytes =
|
|
88
|
+
intermediatesB64.length === 0 ? [] : intermediatesB64.split(",").map((p) => fromBase64Url(p));
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
errors.push({ message: `base64url decode failed: ${messageOf(err)}` });
|
|
92
|
+
return finalize();
|
|
93
|
+
}
|
|
94
|
+
let leaf;
|
|
95
|
+
let intermediates;
|
|
96
|
+
let rootCerts;
|
|
97
|
+
try {
|
|
98
|
+
leaf = new x509.X509Certificate(toArrayBuffer(leafBytes));
|
|
99
|
+
intermediates = intermediatesBytes.map((b) => new x509.X509Certificate(toArrayBuffer(b)));
|
|
100
|
+
const pems = opts.rootPems ?? DEFAULT_ANDROID_KEYSTORE_TRUST_ANCHORS;
|
|
101
|
+
rootCerts = pems.map((pem) => new x509.X509Certificate(pem));
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
errors.push({ message: `x509 parse: ${messageOf(err)}` });
|
|
105
|
+
return finalize();
|
|
106
|
+
}
|
|
107
|
+
const nowDate = new Date(opts.now ? opts.now() : Date.now());
|
|
108
|
+
// ── Chain verification ────────────────────────────────────────────
|
|
109
|
+
try {
|
|
110
|
+
const chainResult = await verifyChain({ leaf, intermediates, pinnedRoots: rootCerts, nowDate });
|
|
111
|
+
cert_chain_valid = chainResult.valid;
|
|
112
|
+
if (!cert_chain_valid) {
|
|
113
|
+
errors.push({ message: chainResult.reason });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
errors.push({ message: `chain verify crashed: ${messageOf(err)}` });
|
|
118
|
+
return finalize();
|
|
119
|
+
}
|
|
120
|
+
// ── Revocation lookup (leaf serial) ──────────────────────────────
|
|
121
|
+
// The leaf serial is the device-attestation key's serial; Google
|
|
122
|
+
// adds it to https://android.googleapis.com/attestation/status when
|
|
123
|
+
// a leaked keybox is detected. Caller-supplied snapshot.
|
|
124
|
+
const snapshot = opts.revocationSnapshot ?? EMPTY_REVOCATION_SNAPSHOT;
|
|
125
|
+
const leafSerialLower = leaf.serialNumber.toLowerCase();
|
|
126
|
+
const revocation = snapshot.entries[leafSerialLower];
|
|
127
|
+
if (revocation) {
|
|
128
|
+
errors.push({
|
|
129
|
+
message: `leaf cert revoked (serial=${leafSerialLower}, status=${revocation.status}${revocation.reason ? `, reason=${revocation.reason}` : ""})`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const revocationOk = !revocation;
|
|
133
|
+
// ── Key Attestation extension ─────────────────────────────────────
|
|
134
|
+
let keyDescription = null;
|
|
135
|
+
const extension = leaf.getExtension(ANDROID_KEY_ATTESTATION_OID);
|
|
136
|
+
if (!extension) {
|
|
137
|
+
errors.push({
|
|
138
|
+
message: `leaf cert missing Android Key Attestation extension (OID ${ANDROID_KEY_ATTESTATION_OID}) — not a hardware-attested leaf`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
try {
|
|
143
|
+
keyDescription = parseKeyDescription(new Uint8Array(extension.value));
|
|
144
|
+
attestation_security_level = keyDescription.attestationSecurityLevel;
|
|
145
|
+
verified_boot_state = keyDescription.hardwareEnforced.rootOfTrust?.verifiedBootState ?? null;
|
|
146
|
+
const constraintsOk = applyExtensionConstraints(keyDescription, opts, errors);
|
|
147
|
+
attestation_extension_valid = constraintsOk && revocationOk;
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
errors.push({ message: `Key Attestation extension parse: ${messageOf(err)}` });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ── Identity binding ──────────────────────────────────────────────
|
|
154
|
+
if (keyDescription) {
|
|
155
|
+
identity_bound = await applyIdentityBinding(keyDescription.attestationChallenge, opts, errors);
|
|
156
|
+
}
|
|
157
|
+
return finalize();
|
|
158
|
+
function finalize() {
|
|
159
|
+
return {
|
|
160
|
+
valid: cert_chain_valid && attestation_extension_valid && identity_bound,
|
|
161
|
+
cert_chain_valid,
|
|
162
|
+
attestation_extension_valid,
|
|
163
|
+
identity_bound,
|
|
164
|
+
attestation_security_level,
|
|
165
|
+
verified_boot_state,
|
|
166
|
+
errors,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Apply the policy constraints to the parsed `KeyDescription`. Returns
|
|
172
|
+
* `true` only if every constraint passed; returns `false` and pushes
|
|
173
|
+
* a structured error otherwise. Multiple failures accumulate so the
|
|
174
|
+
* caller sees the full picture.
|
|
175
|
+
*/
|
|
176
|
+
function applyExtensionConstraints(kd, opts, errors) {
|
|
177
|
+
let ok = true;
|
|
178
|
+
// attestationVersion floor
|
|
179
|
+
const minAttestationVersion = opts.minAttestationVersion ?? 3;
|
|
180
|
+
if (kd.attestationVersion < minAttestationVersion) {
|
|
181
|
+
errors.push({
|
|
182
|
+
message: `attestationVersion ${kd.attestationVersion} below minimum ${minAttestationVersion} (Keymaster 3 / Android 7+)`,
|
|
183
|
+
});
|
|
184
|
+
ok = false;
|
|
185
|
+
}
|
|
186
|
+
// attestationSecurityLevel floor — software-only fallback rejected
|
|
187
|
+
const minSecurityLevel = opts.minSecurityLevel ?? SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
|
|
188
|
+
if (kd.attestationSecurityLevel < minSecurityLevel) {
|
|
189
|
+
errors.push({
|
|
190
|
+
message: `attestationSecurityLevel ${kd.attestationSecurityLevel} below minimum ${minSecurityLevel} (TRUSTED_ENVIRONMENT or higher required for canonical hardware attestation)`,
|
|
191
|
+
});
|
|
192
|
+
ok = false;
|
|
193
|
+
}
|
|
194
|
+
// hardwareEnforced.rootOfTrust must be present with allowlisted
|
|
195
|
+
// verifiedBootState. The default allowlist is [VERIFIED] —
|
|
196
|
+
// user-unlocked devices are rejected at the canonical floor;
|
|
197
|
+
// GrapheneOS-style SELF_SIGNED can be opted in by the operator.
|
|
198
|
+
const allowlist = opts.verifiedBootStateAllowlist ?? [VERIFIED_BOOT_STATE_VERIFIED];
|
|
199
|
+
const rot = kd.hardwareEnforced.rootOfTrust;
|
|
200
|
+
if (!rot) {
|
|
201
|
+
errors.push({
|
|
202
|
+
message: "hardwareEnforced.rootOfTrust missing — cannot certify boot-image state",
|
|
203
|
+
});
|
|
204
|
+
ok = false;
|
|
205
|
+
}
|
|
206
|
+
else if (allowlist.length > 0 && !allowlist.includes(rot.verifiedBootState)) {
|
|
207
|
+
errors.push({
|
|
208
|
+
message: `verifiedBootState ${rot.verifiedBootState} not in allowlist [${allowlist.join(", ")}]`,
|
|
209
|
+
});
|
|
210
|
+
ok = false;
|
|
211
|
+
}
|
|
212
|
+
// attestationApplicationId binding — exact byte match. Per AOSP
|
|
213
|
+
// convention since Keymaster 4 (2018), the field lives in
|
|
214
|
+
// `softwareEnforced` because the framework computes the package
|
|
215
|
+
// signing-cert hash, not the TEE. Older Keymaster 3 chains placed
|
|
216
|
+
// it in `hardwareEnforced`. Accept either; software-enforcement is
|
|
217
|
+
// sufficient because the framework binding is not the attack surface
|
|
218
|
+
// motebit gates on (chain + boot state + identity binding are).
|
|
219
|
+
const expectedAppId = opts.expectedAttestationApplicationId;
|
|
220
|
+
const actualAppId = kd.hardwareEnforced.attestationApplicationId ?? kd.softwareEnforced.attestationApplicationId;
|
|
221
|
+
if (!actualAppId) {
|
|
222
|
+
errors.push({
|
|
223
|
+
message: "attestationApplicationId missing from both hardwareEnforced and softwareEnforced — cannot bind to package identity",
|
|
224
|
+
});
|
|
225
|
+
ok = false;
|
|
226
|
+
}
|
|
227
|
+
else if (!bytesEq(actualAppId, expectedAppId)) {
|
|
228
|
+
errors.push({
|
|
229
|
+
message: `attestationApplicationId does not match expected package binding (${actualAppId.length}B leaf vs ${expectedAppId.length}B expected)`,
|
|
230
|
+
});
|
|
231
|
+
ok = false;
|
|
232
|
+
}
|
|
233
|
+
return ok;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Apply the cross-stack identity binding: SHA-256 the JCS canonical
|
|
237
|
+
* body naming the caller's identity, byte-compare against the leaf's
|
|
238
|
+
* `attestationChallenge`. Returns true on success; pushes structured
|
|
239
|
+
* errors on each missing or mismatched field.
|
|
240
|
+
*/
|
|
241
|
+
async function applyIdentityBinding(challenge, opts, errors) {
|
|
242
|
+
if (typeof opts.expectedIdentityPublicKeyHex !== "string" ||
|
|
243
|
+
opts.expectedIdentityPublicKeyHex.length === 0) {
|
|
244
|
+
errors.push({ message: "identity_bound: expectedIdentityPublicKeyHex not supplied" });
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
if (typeof opts.expectedMotebitId !== "string" || opts.expectedMotebitId.length === 0) {
|
|
248
|
+
errors.push({
|
|
249
|
+
message: "identity_bound: expectedMotebitId not supplied (required for body re-derivation)",
|
|
250
|
+
});
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
if (typeof opts.expectedDeviceId !== "string" || opts.expectedDeviceId.length === 0) {
|
|
254
|
+
errors.push({
|
|
255
|
+
message: "identity_bound: expectedDeviceId not supplied (required for body re-derivation)",
|
|
256
|
+
});
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
if (typeof opts.expectedAttestedAt !== "number" || !Number.isFinite(opts.expectedAttestedAt)) {
|
|
260
|
+
errors.push({
|
|
261
|
+
message: "identity_bound: expectedAttestedAt not supplied (required for body re-derivation)",
|
|
262
|
+
});
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
const canonicalBody = buildCanonicalAttestationBody({
|
|
266
|
+
attested_at: opts.expectedAttestedAt,
|
|
267
|
+
device_id: opts.expectedDeviceId,
|
|
268
|
+
identity_public_key: opts.expectedIdentityPublicKeyHex.toLowerCase(),
|
|
269
|
+
motebit_id: opts.expectedMotebitId,
|
|
270
|
+
});
|
|
271
|
+
const derived = await sha256Bytes(new TextEncoder().encode(canonicalBody));
|
|
272
|
+
if (bytesEq(derived, challenge))
|
|
273
|
+
return true;
|
|
274
|
+
errors.push({
|
|
275
|
+
message: "identity_bound: reconstructed SHA256(canonical body) does not equal leaf attestationChallenge — body naming the caller's identity was not the body the device attested over",
|
|
276
|
+
});
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
280
|
+
/** OID for X.509 basic-constraints extension. */
|
|
281
|
+
const BASIC_CONSTRAINTS_OID = "2.5.29.19";
|
|
282
|
+
/**
|
|
283
|
+
* Walk the cert chain from leaf → intermediates → pinned anchor.
|
|
284
|
+
* Mirrors the App Attest / TPM chain verifier invariants:
|
|
285
|
+
* 1. `X509ChainBuilder.build(leaf)` returns a chain terminating at
|
|
286
|
+
* a self-signed cert reachable from the supplied + pinned pool.
|
|
287
|
+
* 2. The terminal cert's DER byte-equals one of the pinned roots.
|
|
288
|
+
* 3. Every non-leaf cert carries `basicConstraints.cA === true`.
|
|
289
|
+
* 4. Every signature verifies under its issuer's public key.
|
|
290
|
+
* 5. Every cert is within its validity window at `nowDate`.
|
|
291
|
+
*/
|
|
292
|
+
async function verifyChain(input) {
|
|
293
|
+
const { leaf, intermediates, pinnedRoots, nowDate } = input;
|
|
294
|
+
if (pinnedRoots.length === 0) {
|
|
295
|
+
return { valid: false, reason: "no pinned trust anchors configured" };
|
|
296
|
+
}
|
|
297
|
+
const builder = new x509.X509ChainBuilder({
|
|
298
|
+
certificates: [leaf, ...intermediates, ...pinnedRoots],
|
|
299
|
+
});
|
|
300
|
+
const chain = await builder.build(leaf);
|
|
301
|
+
const terminal = chain[chain.length - 1];
|
|
302
|
+
const terminalSelfSigned = await terminal.isSelfSigned();
|
|
303
|
+
if (!terminalSelfSigned) {
|
|
304
|
+
return { valid: false, reason: "chain does not terminate at a self-signed root" };
|
|
305
|
+
}
|
|
306
|
+
const terminalDer = new Uint8Array(terminal.rawData);
|
|
307
|
+
const matchesPinned = pinnedRoots.some((root) => bytesEq(terminalDer, new Uint8Array(root.rawData)));
|
|
308
|
+
if (!matchesPinned) {
|
|
309
|
+
return {
|
|
310
|
+
valid: false,
|
|
311
|
+
reason: "chain terminal cert DER does not match any pinned Google Hardware Attestation root (RSA / ECDSA P-384)",
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
for (let i = 0; i < chain.length; i++) {
|
|
315
|
+
const cert = chain[i];
|
|
316
|
+
if (nowDate < cert.notBefore || nowDate > cert.notAfter) {
|
|
317
|
+
return {
|
|
318
|
+
valid: false,
|
|
319
|
+
reason: `cert at chain position ${i} is outside its validity window at ${nowDate.toISOString()}`,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
const isLeaf = i === 0;
|
|
323
|
+
if (!isLeaf && !certHasCaTrue(cert)) {
|
|
324
|
+
return {
|
|
325
|
+
valid: false,
|
|
326
|
+
reason: `cert at chain position ${i} lacks basicConstraints.cA=true (CA constraint not enforced)`,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
const issuer = i === chain.length - 1 ? cert : chain[i + 1];
|
|
330
|
+
const sigOk = await cert.verify({ publicKey: issuer.publicKey, date: nowDate });
|
|
331
|
+
if (!sigOk) {
|
|
332
|
+
return {
|
|
333
|
+
valid: false,
|
|
334
|
+
reason: `cert at chain position ${i} signature did not verify under its issuer's public key`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return { valid: true, reason: "ok" };
|
|
339
|
+
}
|
|
340
|
+
function certHasCaTrue(cert) {
|
|
341
|
+
const ext = cert.getExtension(BASIC_CONSTRAINTS_OID);
|
|
342
|
+
if (!ext)
|
|
343
|
+
return false;
|
|
344
|
+
return ext.ca === true;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Reconstruct the byte-identical canonical body the Kotlin
|
|
348
|
+
* `expo-android-keystore` mint path composes at attestation time.
|
|
349
|
+
*
|
|
350
|
+
* Ordering: alphabetical (JCS):
|
|
351
|
+
* attested_at, device_id, identity_public_key, motebit_id, platform,
|
|
352
|
+
* version.
|
|
353
|
+
*
|
|
354
|
+
* `platform` is always `"android_keystore"` and `version` is always
|
|
355
|
+
* `"1"` — both constants, matching the App Attest / TPM canonical-body
|
|
356
|
+
* shape exactly.
|
|
357
|
+
*/
|
|
358
|
+
function buildCanonicalAttestationBody(input) {
|
|
359
|
+
return (`{"attested_at":${input.attested_at}` +
|
|
360
|
+
`,"device_id":${jsonEscapeString(input.device_id)}` +
|
|
361
|
+
`,"identity_public_key":${jsonEscapeString(input.identity_public_key)}` +
|
|
362
|
+
`,"motebit_id":${jsonEscapeString(input.motebit_id)}` +
|
|
363
|
+
`,"platform":"android_keystore"` +
|
|
364
|
+
`,"version":"1"}`);
|
|
365
|
+
}
|
|
366
|
+
function jsonEscapeString(s) {
|
|
367
|
+
let out = '"';
|
|
368
|
+
for (const ch of s) {
|
|
369
|
+
const code = ch.codePointAt(0);
|
|
370
|
+
if (ch === '"')
|
|
371
|
+
out += '\\"';
|
|
372
|
+
else if (ch === "\\")
|
|
373
|
+
out += "\\\\";
|
|
374
|
+
else if (ch === "\n")
|
|
375
|
+
out += "\\n";
|
|
376
|
+
else if (ch === "\r")
|
|
377
|
+
out += "\\r";
|
|
378
|
+
else if (ch === "\t")
|
|
379
|
+
out += "\\t";
|
|
380
|
+
else if (code < 0x20)
|
|
381
|
+
out += `\\u${code.toString(16).padStart(4, "0")}`;
|
|
382
|
+
else
|
|
383
|
+
out += ch;
|
|
384
|
+
}
|
|
385
|
+
out += '"';
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
async function sha256Bytes(data) {
|
|
389
|
+
const buf = await globalThis.crypto.subtle.digest("SHA-256", data);
|
|
390
|
+
return new Uint8Array(buf);
|
|
391
|
+
}
|
|
392
|
+
function bytesEq(a, b) {
|
|
393
|
+
if (a.length !== b.length)
|
|
394
|
+
return false;
|
|
395
|
+
for (let i = 0; i < a.length; i++)
|
|
396
|
+
if (a[i] !== b[i])
|
|
397
|
+
return false;
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
function toArrayBuffer(bytes) {
|
|
401
|
+
const copy = new Uint8Array(bytes.length);
|
|
402
|
+
copy.set(bytes);
|
|
403
|
+
return copy.buffer;
|
|
404
|
+
}
|
|
405
|
+
function fromBase64Url(str) {
|
|
406
|
+
let b64 = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
407
|
+
const pad = b64.length % 4;
|
|
408
|
+
if (pad === 2)
|
|
409
|
+
b64 += "==";
|
|
410
|
+
else if (pad === 3)
|
|
411
|
+
b64 += "=";
|
|
412
|
+
else if (pad === 1)
|
|
413
|
+
throw new Error("invalid base64url length");
|
|
414
|
+
const binary = atob(b64);
|
|
415
|
+
const out = new Uint8Array(binary.length);
|
|
416
|
+
for (let i = 0; i < binary.length; i++)
|
|
417
|
+
out[i] = binary.charCodeAt(i);
|
|
418
|
+
return out;
|
|
419
|
+
}
|
|
420
|
+
function messageOf(err) {
|
|
421
|
+
return err instanceof Error ? err.message : String(err);
|
|
422
|
+
}
|
|
423
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@motebit/crypto-android-keystore",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Apache-2.0 verifier for Android Hardware-Backed Keystore Attestation hardware-attestation credentials — offline X.509 chain verification against pinned Google Hardware Attestation roots (RSA-4096 + ECDSA P-384), plus ASN.1 extraction of the KeyDescription extension. Plugs into @motebit/crypto's HardwareAttestationVerifiers dispatcher to validate Android device-attested motebit identities.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist/**/*.js",
|
|
16
|
+
"dist/**/*.js.map",
|
|
17
|
+
"dist/**/*.d.ts",
|
|
18
|
+
"dist/**/*.d.ts.map",
|
|
19
|
+
"LICENSE",
|
|
20
|
+
"NOTICE",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"license": "Apache-2.0",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"motebit",
|
|
27
|
+
"android",
|
|
28
|
+
"keystore",
|
|
29
|
+
"key-attestation",
|
|
30
|
+
"hardware-attestation",
|
|
31
|
+
"attestation",
|
|
32
|
+
"trusted-environment",
|
|
33
|
+
"strongbox",
|
|
34
|
+
"x509",
|
|
35
|
+
"verify"
|
|
36
|
+
],
|
|
37
|
+
"homepage": "https://github.com/motebit/motebit/tree/main/packages/crypto-android-keystore#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/motebit/motebit/issues"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/motebit/motebit",
|
|
44
|
+
"directory": "packages/crypto-android-keystore"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"motebit": {
|
|
50
|
+
"implements": [
|
|
51
|
+
"spec/credential-v1.md"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@peculiar/asn1-schema": "^2.6.0",
|
|
56
|
+
"@peculiar/x509": "^1.12.0",
|
|
57
|
+
"@motebit/protocol": "1.1.0",
|
|
58
|
+
"@motebit/crypto": "1.1.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@noble/curves": "~1.9.0",
|
|
62
|
+
"@noble/hashes": "~1.6.0",
|
|
63
|
+
"@peculiar/webcrypto": "^1.5.0",
|
|
64
|
+
"@types/node": "^22.0.0",
|
|
65
|
+
"typescript": "^5.6.0",
|
|
66
|
+
"vitest": "^2.1.0"
|
|
67
|
+
},
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=20"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "tsc -b",
|
|
73
|
+
"test": "vitest run",
|
|
74
|
+
"test:coverage": "vitest run --coverage",
|
|
75
|
+
"typecheck": "tsc --noEmit",
|
|
76
|
+
"lint": "eslint --parser-options=project:tsconfig.eslint.json src/",
|
|
77
|
+
"lint:pack": "publint --strict && attw --pack --profile esm-only",
|
|
78
|
+
"clean": "rm -rf dist .turbo *.tsbuildinfo"
|
|
79
|
+
}
|
|
80
|
+
}
|