🌊

Nordic nRF52840 Dongle でセキュリティキーを自作する

2022/06/19に公開

はじめに

これは備忘録です。

Nordic nRF52840 Dongleっていう基盤がありまして、これに OSS の OpenSK っていうファームを書き込んでFIDO2のセキュリティキーにしたっていう話です。

OpenSKのReadMeの手順の通りでまあまあうまくいかなったことをメモっています。

2022/6/19時点の情報です。超雰囲気でとりあえず動いたんでOK、ってとこまでやっているんでそれで本当にいいのかは不明です。

参考

概要

  • Nordic nRF52840 Dongle を買う

  • macを用意する(M1だとダメだったのでIntelのmacにすること

  • OpenSKをクローンする

  • macのUSBにNordic nRF52840 Dongleを挿して色々コマンド打って書き込む

最短ルートでやる場合、

    1. Installation guideにそって実施する
    1. 証明書を出してこない
    1. Flashing a firmware - Nordic nRF52840 Dongle
    1. 証明書を書き込む
    1. 動作確認

でやればいいかと思いますが、ハマった順に書いていきます。

1. Installation guideにそって実施する

https://github.com/google/OpenSK/blob/stable/docs/install.md

OpenSKのReadMeでは Segger J-Link など色々必要そうなことが書いてありますが、不要です。

setup.shを実行する

何も読まずに とりあえず setup.sh を実行します。

git clone https://github.com/google/OpenSK.git
cd OpenSK
./setup.sh

成功した場合こんな感です。

gebo OpenSK[stable] % ./setup.sh
[-] Copying additional boards to Tock... DONE.
[-] Applying patch "01-persistent-storage.patch"... DONE.
[-] Applying patch "02-usb.patch"... DONE.
[-] Applying patch "03-usb-debugging.patch"... DONE.
[-] Applying patch "04-additional-boards.patch"... DONE.
[-] Applying patch "05-mpu-fix.patch"... DONE.
[-] Applying patch "06-update-uicr.patch"... DONE.
[-] Applying patch "07-firmware-protect.patch"... DONE.
Signature ok
subject=/CN=OpenSK CA
Getting Private key
Signature ok
subject=/CN=OpenSK Hacker Edition
Getting CA Private Key
Requirement already satisfied: testresources in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (2.0.1)
Requirement already satisfied: pbr>=1.8 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (from testresources) (5.9.0)
info: syncing channel updates for 'nightly-2020-06-10-x86_64-apple-darwin'

  nightly-2020-06-10-x86_64-apple-darwin unchanged - rustc 1.46.0-nightly (feb3536eb 2020-06-09)

info: checking for self-updates
Requirement already satisfied: tockloader==1.5 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (1.5.0)
Requirement already satisfied: six in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (1.16.0)
Requirement already satisfied: intelhex in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (2.3.0)
Requirement already satisfied: argcomplete>=1.8.2 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (from tockloader==1.5) (2.0.0)
Requirement already satisfied: colorama>=0.3.7 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (from tockloader==1.5) (0.4.5)
Requirement already satisfied: pyserial>=3.0.1 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (from tockloader==1.5) (3.5)
Requirement already satisfied: pytoml>=0.1.11 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (from tockloader==1.5) (0.1.21)
Requirement already satisfied: crcmod>=1.7 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (from tockloader==1.5) (1.7)
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: syncing channel updates for 'stable-x86_64-apple-darwin'

  stable-x86_64-apple-darwin unchanged - rustc 1.61.0 (fe5b13d68 2022-05-18)

info: checking for self-updates
     Ignored package `elf2tab v0.6.0` is already installed, use --force to override
warning: be sure to add `elf2tab/bin` to your PATH to be able to run the installed binaries
Requirement already satisfied: colorama in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (0.4.5)
Requirement already satisfied: tqdm in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (4.64.0)
Requirement already satisfied: cryptography in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (37.0.2)
Requirement already satisfied: fido2>=0.9.1 in /Users/suzuki/Library/Python/3.9/lib/python/site-packages (1.0.0)
Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.9/site-packages (from cryptography) (1.14.5)
Requirement already satisfied: pycparser in /usr/local/lib/python3.9/site-packages (from cffi>=1.12->cryptography) (2.20)

確認

crypto_data ディレクトリに以下のようなファイルができていればOKです。

gebo OpenSK+[stable] % tree crypto_data             
crypto_data
├── aaguid.txt
├── opensk.key
├── opensk_ca.csr
├── opensk_ca.key
├── opensk_ca.pem
├── opensk_ca.srl
├── opensk_cert.csr
└── opensk_cert.pem

注意

ここで ./tools/configure.py を実行する手順が書いてありますが、このタイミングでは必ず失敗します。

ファームを書き込んだ後に実施する事なので、次の手順に進みます。

2. Flashing a firmware - Nordic nRF52840 Dongle

https://github.com/google/OpenSK/blob/stable/docs/boards/nrf52840_dongle.md

ファームを書き込む

以下のコマンドで実行します。

./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu

失敗例

nrfutilが見当たらないっていうエラーが出た場合。

gebo OpenSK[stable] % ./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu
fatal: Couldn't find nrfutil binary. Make sure it is installed and that your PATH is set correctly.

nrfutilのサイトから入れます。

pip install nrfutil

2022/6/19時点 だと Successfully installed nrfutil-6.1.3 が入ります。

成功例

以下のようなメッセージが出たら成功です、次に進みます。

info: Please insert the dongle and switch it to DFU mode by keeping the button pressed while inserting...
info: Press [ENTER] when ready.

DFUモードにする

Nordic nRF52840 Dongle をDFUモード(書き込みモード)にします。

  • mac のUSB に Nordic nRF52840 Dongle を指す
  • Nordic nRF52840 DongleのLEDが赤くゆっくり点滅してれば既にDFUモードになっているのでOK(購入した初期状態はこうなっている)
  • Nordic nRF52840 DongleのLEDがついてない場合は白いボタンと、その横にあるめっちゃ小さい横向きのボタン2つのボタンを同時に押す→LEDが赤くゆっくり点滅し始めるとDFUモードになったということなのでOK

ファーム書き込む

DFUモードにして [ENTER] します。

info: Flashing device using DFU...
  [####################################]  100%          
Device programmed.

これでOKです。

3. 証明書を書き込む

ここまでの作業でなんとなくセキュリティキーとしてセットアップ完了しますが、なんか動きません。

サイトとかブラウザによってうまく認識しないのです。特に、登録ができません。

よく調べると Register 時に返却される Attestaion に証明書が入っていません。これが原因で弾かれている模様です。

configure.pyでAttestaionの証明書を書き込む

ここで、以下のコマンドを実行します。

失敗したときの挙動が初見殺しなので失敗時の挙動をメモっておきます。

./tools/configure.py \
    --certificate=crypto_data/opensk_cert.pem \
    --private-key=crypto_data/opensk.key

失敗時のログ - その1

これは失敗しています。(初見ではエラーかどうか判別付きません)

gebo OpenSK[stable] % ./tools/configure.py \
    --certificate=crypto_data/opensk_cert.pem \
    --private-key=crypto_data/opensk.key
info: Private key is valid.
info: Certificate is valid.
0it [00:00, ?it/s]

原因

  • Nordic nRF52840 Dongleがmacに刺さっていないと失敗する
  • Nordic nRF52840 Dongleにファームがちゃんと書き込まれていないと失敗する
  • Nordic nRF52840 DongleがDFUモードになっていると失敗する

失敗時のログ - その2

これも失敗しています。

gebo OpenSK[stable] % ./tools/configure.py \
    --certificate=crypto_data/opensk_cert.pem \
    --private-key=crypto_data/opensk.key
info: Private key is valid.
info: Certificate is valid.
Traceback (most recent call last):
  File "/Users/suzuki/Documents/GitHub/OpenSK/./tools/configure.py", line 196, in <module>
    main(parser.parse_args())
  File "/Users/suzuki/Documents/GitHub/OpenSK/./tools/configure.py", line 127, in main
    for authenticator in tqdm(get_opensk_devices(args.batch)):
  File "/Users/suzuki/Documents/GitHub/OpenSK/./tools/configure.py", line 65, in get_opensk_devices
    return [ctap2.CTAP2(dev)]
AttributeError: module 'fido2.ctap2' has no attribute 'CTAP2'

よく見ると pyでエラー吐いています。Yubikoの fido2.ctap2 を使ってコマンドを送っているようなのですが、その使い方が間違っているようです。

configure.py の line 65 を修正します。

修正前: return [ctap2.CTAP2(dev)]
↓
修正後: return [ctap2.Ctap2(dev)]

成功時のログ

成功するとこうなります。

gebo OpenSK[stable] % ./tools/configure.py \
    --certificate=crypto_data/opensk_cert.pem \
    --private-key=crypto_data/opensk.key
info: Private key is valid.
info: Certificate is valid.
info: Programming OpenSK device AAGUID 499c5cda-665d-419c-bf83-db2f4a1e215b (CtapHidDevice('4298835323')).                                                            
info: Please touch the device to confirm...                                                                                                                           
info: Certificate: Present                                                                                                                                            
info: Private Key: Present                                                                                                                                            
100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:13<00:00, 13.89s/it]

4. 証明書を出してこない

上記 2で Nordic nRF52840 Dongle に証明書を書き込みました。これでRegister 時に返却される Attestaion に証明書が入ってくるはずです。

が、まだ Attestaion に証明書が入っていません(怒)

今度は Attestaion に証明書を返すように Dongle の動作設定をする必要があります。

mod.rs の USE_BATCH_ATTESTATION を true にします。

修正前: const USE_BATCH_ATTESTATION: bool = false;
↓
修正後: const USE_BATCH_ATTESTATION: bool = true;

これで以下のコマンドでファームを書き込みます。

./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu

5. 動作確認

お疲れさまでした

手順書のメンテは大事だぞっ!

Discussion