BLEタグ は1個なら安いが、1万個になると話が変わる。フリートが工場を出る瞬間、すべてのタグはすでに一意で信頼できるIDを持っていなければならない。さもないと「資産追跡」システムは、誰でもクローンできる「匿名ビーコン spam」システムに過ぎなくなる。量産プロビジョニングと安全な登録は、タグが資産になるか負債になるかを決める地味だが重要な工程だ。
本稿は、数百万のタグにデバイスごとの信頼を組み込むエンジニアのガイドである。鍵注入、セキュアエレメント対SoC格納、工場フロー、ゼロタッチ登録、ライフサイクル中のローテーションを扱う。
2つのフェーズ、1つの信頼チェーン
- 製造プロビジョニング:ラインで1回だけ。タグがID(鍵ペア、シリアル、アテステーション)を得る
- 現場登録(enrollment):顧客システムに初めて参加するとき。工場IDをテナント・サイト・ポリシーに紐づける
両者を混同するのは典型的なミス。工場が空白や共有鍵を出荷したら、現場で信頼を後から作れない。
デバイスごとのID:実際に何を入れるか
各タグには以下が必要:
- 一意の鍵ペア(ECDSA P-256 または Ed25519)— 秘密鍵はデバイス外に出ない
- サーバが検証できる公開ID:生公開鍵、またはフリートルート署名X.509証明書
- その鍵に紐づくシリアル/EUI-64。同じセキュアストアに書く
- 任意で、シリコンばらつき由来のPUF導出秘密(クローン防止)
署名IDなしにランダムMACだけを送るタグは簡単に偽装できる。署名済み公開鍵こそが「このタグはシリアルX」をサーバが信じる根拠だ。
セキュアエレメント対SoC格納
| 方式 | 鍵抽出リスク | 単価 | 柔軟性 | プロビジョニング |
|---|---|---|---|---|
| SoC鍵 in フラッシュ | 高(リード/JTAG) | 低 | 高 | OTP/eFuse封印 |
| SoC鍵 in eFuse | 中(デカップ要) | 低 | 中 | 1回焼き込み |
| 独立セキュアエレメント | 極低 | +$0.30–1 | 低 | 工場で初期化 |
| PUF + SoC | 低(保存鍵無) | 中 | 中 | 起動時導出 |
管理外に出る資産タグには、セキュアエレメントかPUFがコストに値する。平フラッシュ鍵は物理的に守られたクローズド用途のみ許容。
工場プロビジョニングフロー
注入ステーションが信頼の始まり。最小で監査可能なフロー:
1. SoCはプロビジョニングモードで起動(JTAG開、デバッグ有効)
2. オンチップTRNGが鍵ペア生成 (kp_priv, kp_pub)
3. ステーションがシリアル+kp_pubをOTP/eFuseまたはSEへ書く
4. ステーションが (シリアル, kp_pub) をPLANT_KEYで署名 -> アテステーション
5. ステーションがデバイス封印:デバッグロック、OTPロック、再プロビ不可
6. デバイスがチャレンジにアテステーション返却 -> ステーションHSM監査へ記録
鉄則:秘密鍵はデバイス上で生成、ステーション上では絶対に作らない。ステーションが秘密鍵を持てば、盗まれたステーション=クローンされたフリート。アテステーション署名のPLANT_KEYはHSMにあり、ラップトップには置かない。
サプライチェーンの信頼
アテステーションは、タグが偽物でなく自社ライン由来であることを登録サーバに証明する。チェーンせよ:
DEVICE_KEY ← PLANT_KEY署名 ← FLEET_ROOT署名
署名済みマニフェスト(シリアル、公開鍵ハッシュ、バッチ、時刻)をHSM裏付の追記専用監査ログに保存。バッチが漏洩しても、フリート全体ではなくそのバッチに限定して失効できる。
ゼロタッチ現場登録
タグは顧客サイトで初通電したときに自分で登録すべき:
タグ通電 -> ENROLLMENT_ADV送信 (シリアル, nonce, アテステーション)
ゲートウェイ受信 -> (シリアル, アテステーション) をENROLLMENT_SERVERへプロキシ
サーバ検証:アテステーション有効? シリアル未使用? 失効無?
サーバ発行:テナント紐づけ + タグごとセッション鍵 + ポリシー
サーバ返却 -> ゲートウェイ転送 -> タグが紐づけ保存、NORMALモードへ
技術者がタグごとQRを読まない。広告の「チャレンジ」が捕捉した登録フレームのリプレイを防ぐ。
登録プロトコルスケッチ
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) # サイト, 資産クラス
binding = sign((serial, tenant, policy), FLEET_KEY)
log_enroll(serial, tenant, now())
return (session_key, binding, policy)
セッション鍵はタグごと・ローテーション。長期デバイス鍵は登録時と定期再アテステーションのみでID証明に使う。
鍵ローテーションとライフサイクル
タグのID鍵は固定でも、セッション/暗号鍵は回す必要がある:
- 再登録ごと(サイト/テナント移動)にローテーション
- 遠隔失効を支援:漏洩タグのシリアルをゲートウェイへCRL配信、以降無視
- 定期再アテステーション(例90日ごと)でデバイスが鍵を保持し続けることを再証明。公開ID漏洩を秘密鍵無しで使い回したクローンを検出
バッチスループット
量産プロビジョニングはライン問題。典型ラインの数値:
| 工程 | タグあたり時間 | 1ステーション処理量 |
|---|---|---|
| 鍵生成+書込 | 40 ms | ~25/秒 |
| アテスト+封印 | 60 ms | ~16/秒 |
| 監査ログ確定 | 20 ms | ~50/秒 |
| 端から端 | ~120 ms | ~8/秒 ≈ 2.9万/時 |
ステーションを並列化し、1シフトで6桁を達成。ボトルネックはほぼ常にHSM署名レートでありSoCではない。
現場のクローン防止
登録鍵があっても、粘着なクローンは捕捉フレームをリプレイする。対策:
- PUFチャレンジ応答:サーバが乱数チャレンジ、本物シリコンのみ正応答(抽出鍵無)
- ムービングターゲット:広告IDを回す、または回転匿名アドレス(反追跡記事参照)
- 振る舞いチェック:動かない/不可能な速さで動くクローンはサーバで検出可能
フリートを沈めるミス
- タグ間共有鍵 — 1漏れで全体 compromise、失効不能
- 署名無し平文シリアル — 簡単に偽装
- アテステーション無し — 偽物が本物として登録
- 現場で再プロビ可能 — 拾ったタグをリフラッシュ再登録
- HSM無しPLANT_KEY — ラップトップ上署名鍵は負債
OEMチェックリスト
- [ ] タグごと一意鍵ペア、秘密鍵はデバイス生成
- [ ] 出荷前にセキュアストア封印(eFuse/SE/PUF)
- [ ] アテステーションをフリートルートへチェーン、監査ログ追記専用
- [ ] チャレンジnonce付きゼロタッチ登録
- [ ] タグごとセッション鍵ローテーション+CRL失効
- [ ] 定期再アテステーション有効
- [ ] PLANT_KEYはHSM、ボリュームに合うスループット
正しく作られた BLEタグ は箱を出た瞬間から信頼でき、寿命まで信頼を保つ。プロビジョニングを誤ると、1万個の匿名ビーコンを出荷したことになる。