2017/06/07

[mbedTLS]マルチスレッドでは署名と検証は排他した方が良いのか?

全然そのつもりがなかったのだが、mbedTLSを使って作っていたライブラリをマルチスレッドで動かすことにした。
楕円曲線の署名して送信し、受信したら検証して別のデータをまた送信、というようなことを各スレッドで行うと思っておくれ。


ようやくベースができたので、手動でちょこちょこ通信させていたのだが、たまに検証に失敗することがある。
毎回ならロジックがどこかおかしいと思うのだが、たまに、なのだ。
まれに、というほどでもなく、比較的置きやすいのだが、少なくとも毎回ではない。

なんだ??


検証に失敗するからには、

  • 作った署名が間違っている
  • 署名の送信か受信が間違っている
  • 受信した署名までは正しいが検証で失敗している

のどれかなのだが、ログを出していてもどのスレッドが出しているのかうまく整理できず、何が悪いのかはっきりしない。。。
こういうときって、標準出力ではなく、せめてスレッドごとにログを吐くようにしておけばよいのだろうね。


mbedTLSのマルチスレッド動作については、ページがある。
Thread Safety and Multi Threading: concurrency issues - Knowledge Base - mbed TLS (Previously PolarSSL)

大ざっぱに読んで、MBEDTLS_THREADING_CとMBEDTLS_THREADING_PTHREADを有効にしたライブラリを作ればよいのだろう、と判断。
ただ、ecp.cにはTHREADINGのマクロがあるのだが、ecdsa.cの方にはない。
ヘッダを見ると、mbedtls_ecdsa_write_signature()は同じコンテキストだったらスレッドセーフじゃない、と書いてある。
ecp.cのmbedtls_ecp_mul()なんかもスレッドセーフじゃないというコメントが入っているが、こっちはmbedtls_mutex_lock()で排他しているのだ。

うーーん。。。。

中で呼んでいる関数のどこかで排他されているから大丈夫、というパターンかもしれないが、mbedtls_ecp_mul()なんかは「同じグループだとスレッド-セーフじゃない」といっているから、同じmbedtls_ecp_groupを使い回しているところが全体として危ないのかもしれん。
今回、mbedtls_ecp_groupは全員同じものを使っていいんじゃないの?と思い、開始時に設定したら解放せずに全員が同じものにアクセスするように作り込んでいたのだ。

その考え方自体が間違っているのかもしれんが、MBEDTLS_THREADING_Cなんて用意してあるくらいだから、そんなのしなくてもよいのかも。。。


わからんので、mbedtls_ecdsa_sign_det()やmbedtls_ecdsa_read_signature()は、mbedtls_mutex_lock/unlock()で囲むことにした。


そのおかげか、今のところ安定している。
でも、実はECDSAは直接関係なくて、その付近で使っている変数が問題だったり、あるいは単にタイミングが発生しにくくなっただけという可能性もある。


mbedtls_ecp_groupを共有していることの危険性が分かってないのよねぇ。
暗号化関係って、よくわからない計算をたくさんしているだけに見えてしまい、深く追いたくないのだ、そうもいっていられんのか。


2017/06/14

気になったので、mbedtls_ecp_keypair構造体の構成を見てみた。
mbedtls_ecp_groupではなくmbedtls_ecp_keypairなのは・・・ソースを見直すとkeypairの変数をグローバルで確保し、最初にloadして使い回していたからだ。

typedef struct
{
    mbedtls_ecp_group grp;      /*!<  Elliptic curve and base point     */
    mbedtls_mpi d;              /*!<  our secret value                  */
    mbedtls_ecp_point Q;        /*!<  our public value                  */
}
mbedtls_ecp_keypair;

あー、秘密鍵とか公開鍵をこの中で保持しているじゃないか!
こんな変数を使い回していたら、そりゃよろしくないですわな。。。
コメントにも「Members purposefully in the same order as struc mbedtls_ecdsa_context」となっているので、コンテキストが異なるスレッドからは使ってはいけない代物なのだ。


そういうわけで、毎回スタックでmbedtls_ecp_group_load()して使うようにした。
なんか、暗号化ライブラリって重たい処理をしていそうなので、使い回せるところは使い回した方がよいのではないかと考えてしまったのだ。
でも、それはそれでセキュリティ的によろしくないだろうから、考え直さないと。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。