こんにちは。AndGoのハードウェア担当の片山です。

前回までオープンソースのハードウェアウォレットのColdcard (https://coldcard.com/) について解析してきました。今回はソースコードをより深く解析してみましたのでその一部をご紹介します。Coldcardはオープンソースのハードウェアウォレットでありながら,セキュアエレメントが搭載されています。また,SDカードを経由してトランザクションデータをやりとりするといった特徴もあります。

COLDCARDのファームウェアの概要

Coldcardは主にMicroPythonで書かれています。マイコンのファームウェアは資源が限られていることもあり,フラッシュメモリも1MB程度であることがほとんどです。したがってバイナリサイズが小さくなり,しっかり最適化すれば高速に動作するC/C++で開発することが大半です。しかしC/C++は他の言語と比べるとどうしても生産性の面で劣りますし,一歩間違えると簡単にメモリを破壊してしまうなどの致命的なバグを発生しやすいです。Pythonであればコードも短くかけますし,メモリ管理についてもほとんど気にしなくても済みます。もちろん一般的なPythonがそのまま動作するわけではなく,MicroPythonというマイコン用にコンパイルしてくれるタイプのPythonが使用されています。

Coldcardの場合には動作テスト用にUNIX環境(といいながらもほぼMac)でもエミュレーターのように動かすことができ,前々回の記事でご紹介しました。マイコン用にはC言語で書かれたブートローダーとMicroPythonで書かれた本体という構成になっていますが,ハードウェア依存のブートローダーもPythonで書き換えたものが用意されており,これを使うとColdcardが無くても手元のPCでテストしてみることができ,MicroPythonの移植性の高さに驚きます。

GitHubのリポジトリ(https://github.com/Coldcard/firmware)を見てみると,stm32 と unix というディレクトリがそれぞれマイコン用,PC用のブートローダーが入っており,shareというディレクトリにPythonで書かれた共通するコードが入っています。

署名に関わる部分を探す

ウォレットの一番重要な機能はトランザクションに秘密鍵で署名をする部分です。どこで行われているか探してみます。Coldcardではトランザクションに署名しようとすると,”OK TO SEND?”というメッセージが出てきます(Fig. 1 [画像はhttps://youtu.be/tCOpEkaZ7y4 より])。これを手がかりに検索してみます。リポジトリ(https://github.com/Coldcard/firmware)を開き右上の検索窓に”OK TO SEND?”とダブルクォーテーションをつけて入力して検索してみましょう(Fig. 2)。すると3件ヒットします。3件のうち2件はtestingディレクトリのファイルですので検証用のコードで直接関係はありません。残るshared/auth.pyの478行目が実際に画面に表示している部分です。(2022/2/24時点のコミット(https://github.com/.../322c6e669c19421e77acc8eddb9d6623fa...)ですのでご覧になるタイミングによってわ変わるかもしれません。)

Fig. 1 [画像はhttps://youtu.be/tCOpEkaZ7y4 より

Fig. 2

shared/auth.pyを開き,478行目の下の方を見てみると,”# do the actual signing.”というコメント行があることがあることが分かります。509行目にself.psbt.sign_it()という行があります。GitHub上でクリックすると,sign_it()の定義(shared/psbt.pyというファイルの1400行目から)へ移動することができます。

Fig. 3

さらに下の方を見てみると,1513行目にpk = node.privkey()と書かれています(Fig. 4)。そして1526行目にresult = ngu.secp256k1.sign(pk, digest, retry).to_bytes() の部分が楕円曲線暗号で署名している部分となります。

この署名しているnguというライブラリはMicroPython用のBitcoinライブラリです(https://github.com/switck/libngu) 。Coldcardのセキュアエレメントには楕円曲線暗号の機能が搭載されているので,セキュアエレメント内で署名をしていると思いこんでいましたが,どうやらそうではないようです(2022/02/23の記事ではセキュアエレメントに署名させている部分を紹介しましたが,実際にはその部分は使用されていませんでした。)

Fig. 4

セキュリティに関する考察

ATECC608のデータシート(https://ww1.microchip.com/.../ATECC608A...)をチェックしてみるとECDSAをハードウェアからサポートしているとはかいてあるもののビットコインで使用されているsecp256k1には対応していないので,やはり署名自体はマイコン上で処理されているようです。

ドキュメントを読むと秘密鍵は暗号化されてセキュアエレメントに格納されているとのことですが,セキュアエレメントとマイコンの間の通信を解析したとしても,秘密鍵を盗み出すことはほぼ不可能です。

ただし,もし何らかの方法でマイコンのデバッグモードを有効にできれば,メモリにアクセスできてしまいます。Fig. 4の部分でロードしてきた秘密鍵を見ることが可能になります。しかし,簡単にはマイコンのデバッグモードを有効にすることは難しいですので,現実的には問題はないレベルだと思いますが,セキュアエレメントの強力さが活かしきれていない点が少々残念です。次期バージョンに期待したいと思います。