A BLE Tag is cheap until you have ten thousand of them. The moment a fleet leaves the factory, every tag must already carry a unique, trustworthy identity — otherwise your “asset tracking” system is really an “anonymous beacon spam” system that anyone can clone. Mass provisioning and secure enrollment are the unglamorous steps that decide whether your tags are assets or liabilities.
This is the engineer’s guide to getting per-device trust into millions of tags: key injection, secure-element vs SoC storage, factory flow, zero-touch onboarding, and lifecycle rotation.
Two phases, one trust chain
- Manufacturing provisioning: done once, at the line, where the tag gets its identity (key pair, serial, attestation).
- Field enrollment: done when the tag first joins a customer’s system, binding the factory identity to a tenant, a site, and a policy.
Confusing the two is the classic mistake. You cannot invent trust in the field if the factory shipped a blank or shared key.
Per-device identity: what actually goes in
Every tag needs:
- A unique key pair (ECDSA P-256 or Ed25519) — private key never leaves the device.
- A public identity the server can verify: raw public key, or an X.509 certificate signed by the fleet root.
- A serial / EUI-64 bound to that key, written into the same secure store.
- Optionally a PUF-derived secret from silicon variation, for anti-cloning.
A tag that broadcasts only a random MAC with no signed identity is trivially spoofable. The signed public key is what makes “this tag is serial X” a statement the server can trust.
Secure element vs SoC key storage
| Option | Key extraction risk | Unit cost | Flexibility | Provisioning |
|---|---|---|---|---|
| SoC key in flash | High (readout/JTAG) | Low | High | OTP/eFuse seal |
| SoC key in eFuse | Medium (needs decap) | Low | Medium | One-time burn |
| Discrete secure element | Very low | +$0.30–1 | Low | Personalize at plant |
| PUF + SoC | Low (no key at rest) | Medium | Medium | Derive on boot |
For asset tags that leave your control, a secure element or PUF is worth the cost. A plain flash key is fine only for closed, physically secured deployments.
The factory provisioning flow
The injection station is where trust is born. A minimal, auditable flow:
1. SoC boots in provisioning mode (JTAG open, debug enabled)
2. TRNG on-chip generates key pair (kp_priv, kp_pub)
3. Station writes serial + kp_pub into OTP/eFuse or secure element
4. Station signs (serial, kp_pub) with PLANT_KEY -> attestation token
5. Station seals device: lock debug, lock OTP, disable re-provision
6. Device returns attestation on challenge -> station logs to HSM audit
Critical rule: the private key is generated on the device, never on the station. If the station holds private keys, a stolen station = a cloned fleet. The plant key that signs attestations lives in an HSM, not a laptop.
Supply-chain trust
The attestation token lets the enrollment server prove a tag came from your line, not a counterfeiter. Chain it:
DEVICE_KEY signed by PLANT_KEY signed by FLEET_ROOT
Keep a signed manifest (serial, pubkey hash, batch, timestamp) in an append-only audit log backed by the HSM. If a batch is compromised, you can scope a revocation to that batch instead of the whole fleet.
Zero-touch field enrollment
The tag should enroll itself the first time it is powered in the customer site:
tag powers on -> broadcasts ENROLLMENT_ADV (serial, nonce, attestation)
gateway hears -> proxies (serial, attestation) to ENROLLMENT_SERVER
server verifies: attestation valid? serial unused? not revoked?
server issues: tenant binding + per-tag session key + policy
server returns -> gateway forwards -> tag stores binding, enters NORMAL mode
No technician scans a QR code per tag. The “challenge” in the advertisement prevents a replay of a captured enrollment frame.
Enrollment protocol sketch
def enroll(tag_adv, server):
serial, nonce, attest = parse(tag_adv)
if not verify_attest(attest, serial, PLANT_PUB): return REJECT
if serial in revoked_list: return REJECT
if serial in enrolled_set: return ALREADY
session_key = HKDF(nonce, server_seed)
policy = lookup_policy(serial) # site, asset class
binding = sign((serial, tenant, policy), FLEET_KEY)
log_enroll(serial, tenant, now())
return (session_key, binding, policy)
The session key is per-tag and rotated; the long-term device key is used only to prove identity at enrollment and on periodic re-attestation.
Key rotation and lifecycle
A tag’s identity key can stay fixed, but its session/encryption keys must rotate:
- Rotate on every re-enrollment (tag moves site/tenant).
- Support remote revocation: a compromised tag’s serial goes on a CRL pushed to gateways; it is then ignored.
- Periodic re-attestation (e.g. every 90 days) re-proves the device still holds its key, catching clones that reused a leaked public identity without the private key.
Batch throughput
Mass provisioning is an assembly-line problem. Numbers from a typical line:
| Step | Time per tag | Throughput (1 station) |
|---|---|---|
| Key gen + write | 40 ms | ~25/s |
| Attest + seal | 60 ms | ~16/s |
| Audit log commit | 20 ms | ~50/s |
| End-to-end | ~120 ms | ~8/s ≈ 29k/hour |
Parallelize across stations to hit six figures per shift. The bottleneck is almost always the HSM signing rate, not the SoC.
Anti-cloning in the field
Even with enrolled keys, a determined clone can replay a captured frame. Defenses:
- PUF challenge-response: server sends a random challenge; only the genuine silicon returns the correct response (no key to extract).
- Moving target: rotate the advertised identity or use rotating anonymous addresses (see the anti-tracking article).
- Behavioral check: a clone that never moves or moves impossibly fast is detectable at the server.
Mistakes that sink a fleet
- Shared key across tags — one leak compromises all; revocation is impossible.
- Plaintext serials without signature — trivially spoofed.
- No attestation — counterfeits enroll as real.
- Re-provisionable devices in field — a found tag can be reflashed and re-enrolled.
- HSM-free plant key — the signing key on a laptop is a liability.
OEM checklist
- [ ] Per-tag unique key pair, private key generated on device
- [ ] Secure store sealed (eFuse/secure element/PUF) before ship
- [ ] Attestation chained to fleet root, audit log append-only
- [ ] Zero-touch enrollment with challenge nonce
- [ ] Per-tag session key rotation + CRL revocation
- [ ] Periodic re-attestation enabled
- [ ] Plant key in HSM, throughput sized for volume
A BLE Tag done right is trustworthy the instant it leaves the box and stays trustworthy for its whole life. Get provisioning wrong and you have shipped ten thousand anonymous beacons.