1. はじめに
この記事では、オープンソースプロジェクトのオープン量子安全(OQS: Open Quantum Safe)のライブラリーliboqsとwolfSSLを組み合わせて、TLSでポスト量子暗号を実際に動かして試してみます。前回の「鍵交換」に引き続き今回は「署名」を中心にみていきいます。ポスト量子暗号標準化(Post-Quantum Cryptography Standardization)の背景については「TLSでポスト量子暗号を試してみる (その1:鍵交換)」を参照してください。
2. ポスト量子暗号の署名アルゴリズム
liboqsでは、署名アルゴリズムとしてNISTコンペティション ラウンド3の最終候補 Dilithium, Falcon, Rainbowの3つがサポートされています。
アルゴリズム | 詳細種別 |
---|---|
Dilithium | Dilithium2 Dilithium2-AES Dilithium3 Dilithium3-AES Dilithium5 Dilithium5-AES |
Falcon | Falcon-512 Falcon-1024 |
Rainbow | Rainbow-I-Classic Rainbow-I-Circumzenithal Rainbow-I-Compressed Rainbow-III-Classic Rainbow-III-Circumzenithal Rainbow-III-Compressed Rainbow-V-Classic Rainbow-V-Circumzenithal Rainbow-V-Compressed |
表1: liboqsのサポートするアルゴリズム
署名のためのAPIとしては、鍵ペアの生成、署名、検証などのAPIが用意されていて、概ねこれまでの公開鍵署名と同じようなイメージでプログラムすることができるようになっています。
API名 | 機能 |
---|---|
OQS_SIG_keypair | 鍵ペアの生成 |
OQS_SIG_sign | 署名 |
OQS_SIG_verify | 検証 |
表2:主な署名用API
3. TLS1.3の署名と検証
下の図はTLSの公開鍵証明書を利用した公開鍵署名と検証の関連を示しています。ポスト量子暗号でもこの枠組みはそのまま踏襲します。
サーバ側はサーバ証明書にCAによる署名をもらいます。クライアント側はCA証明書を用意しておきます。TLSハンドシェーク時には、TLS1.3では"Certificate"メッセージでサーバ証明書を送り、"Certificate Verify" でそれまでのハンドシェークメッセージに対する署名を送ります。クライアント側では、受けとったサーバ証明書が真正であることをCA証明書の公開鍵で検証し、サーバ証明書の公開鍵で送られてきた署名を検証します。
図1: TLSの署名と検証
これらの全ての署名、検証をポスト量子アルゴリズムで実現することで、量子コンピューティングの時代において通信相手に対するピア認証が安全にできることになります。
4. サンプルプログラムを動かしてみる
4.1 サンプルのダウンロード
まずは、ポスト量子暗号を使ったTLSサーバ、クライアントのサンプルをwolfSSLのGithubレポジトリからダウンロードします。
$ git clone https://github.com/wolfssl/wolfssl-example
$ cd wolfssl-examples/pq
4.2 サンプル証明書を見てみる
レポジトリをクローンするとサンプルプログラムと同時にwolfssl-examples/certsディレクトリの下にポスト量子暗号(Falcon)によるCA証明書、サーバ証明書、プライベート鍵などのサンプルファイルも格納されています。OpenSSLコマンドを使ってx509ファイルの内容を見てみるのですが、現在の通常版OpenSSLだと公開鍵の部分がまだポスト量子に未対応のために、正しく表示されません。その部分も正しく表示してみたいという場合は次のようにポスト量子暗号対応のバージョンをダウンロード、ビルドして使用します。ただし、このバージョンは暫定バージョンなのでno-sharedでビルドしてインストールせず、本件のためだけにローカルに使用するのがよいと思います。
liboqsのビルドが必要ですが、これのビルド、インストール方法とポスト量子暗号による鍵交換については「TLSでポスト量子暗号を試してみる (その1:鍵交換)」を参照してください。
ポスト量子暗号アルゴリズム部分をきちんと表示させたい場合は、次にliboqs対応版のOpenSSLをダウンロード、ビルドします。その部分は感じだけでよいという場合は通常版のOpenSSLを使います。
$ tar xf openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08.tar.gz
$ cd openssl-OQS-OpenSSL_1_1_1-stable-snapshot-2021-08
$ ./config no-shared
$ make
ビルドが完了したら、ローカルに作成したopensslコマンドを使用してx509サブコマンドでサンプル証明書の内容を見てみます。
公開鍵証明書のアルゴリズムに "Public Key Algorithm: falcon1024" と表示され、たいへん長い鍵の内容が表示されます。また、下部の署名にも "Signature Algorithm: falcon1024" と表示され長い署名の内容が表示されます。
$ ./apps/openssl x509 -in <サンプルRoot>/certs/falcon_level5_root_cert.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1024 (0x400)
Signature Algorithm: falcon1024
Issuer: C = CA, ST = ON, L = Waterloo, O = wolfSSL Inc., OU = Engineering, CN = Root Certificate, emailAddress = root@wolfssl.com
Validity
Not Before: Jan 15 03:39:16 2022 GMT
Not After : Jan 15 03:39:16 2023 GMT
Subject: C = CA, ST = ON, L = Waterloo, O = wolfSSL Inc., OU = Engineering, CN = Root Certificate, emailAddress = root@wolfssl.com
Subject Public Key Info:
Public Key Algorithm: falcon1024
falcon1024 Public-Key:
pub:
0a:8a:50:9f:b6:01:2e:8f:98:5a:a7:9b:05:20:2f:
0a:f8:eb:4b:9e:8e:3b:b2:d6:38:07:dc:5c:17:33:
...
e7:e7:20:41:fa:f9:da:97:26:48:0c:e2:e0:5b:ee:
48:69:0a:8d:f5:0b:f1:98:3d:a2:50:c2:b2:52:ce:
b5:80:2d:95:c9:78:64:3a
X509v3 extensions:
X509v3 Subject Key Identifier:
26:36:0F:AA:53:E3:7B:DF:5C:FC:EC:CE:CF:D7:46:8F:F0:54:22:2F
X509v3 Authority Key Identifier:
keyid:26:36:0F:AA:53:E3:7B:DF:5C:FC:EC:CE:CF:D7:46:8F:F0:54:22:2F
DirName:/C=CA/ST=ON/L=Waterloo/O=wolfSSL Inc./OU=Engineering/CN=Root Certificate/emailAddress=root@wolfssl.com
serial:04:00
X509v3 Key Usage: critical
Certificate Sign
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: falcon1024
3a:cc:5c:5d:00:11:f6:fa:1a:8d:56:1c:5d:a2:94:ea:19:61:
6b:6b:37:67:ce:21:df:b7:e8:ab:a1:df:21:54:97:b3:2d:8f:
...
c4:f9:a5:87:17:ef:97:c9:31:b1:d3:93:7f:b8:bb:38:6c:6b:
02:f0:2a:5b:18:2f:40:95:2b:54:b3:cd
-----BEGIN CERTIFICATE-----
MIIOkDCCCYagAwIBAgICBAAwBwYFK84PAwQwgZYxCzAJBgNVBAYTAkNBMQswCQYD
VQQIDAJPTjERMA8GA1UEBwwIV2F0ZXJsb28xFTATBgNVBAoMDHdvbGZTU0wgSW5j
...
28cMdmpWFmVxK2dJrbXn25qOIgu2fFMD6FS2PelvTejVPpF4Oi515dR6uvhlzKu1
iCAvy8OexPmlhxfvl8kxsdOTf7i7OGxrAvAqWxgvQJUrVLPN
-----END CERTIFICATE-----
通常版のOpenSSLでは、アルゴリズムのOIDが生のまま表示され、内容の表示は残念ながらエラーとなってしまいますが、だいたいの感じは理解できるかと思います。:
Public Key Algorithm: 1.3.9999.3.4
いずれにせよ、これでわかるように現状のポスト量子暗号による公開鍵や署名は少々長くなってしまいます。致命的な長さではないもののこれがTLSハンドシェークとして送られることを考えると改善課題ではあります。
4.3 wolfSSLとサンプルのビルド
最新のwolfSSLライブラリーはポスト量子暗号に対応しているので、TLSによる通信自身については普通のTLSサーバとクライアントを使用してもよいのですがTLS1.3ではハンドシェークメッセージが暗号化されていてそのままでは見えません。これを復号してメッセージを見るためにはサンプルプログラム中にセッション鍵情報を取得する仕掛けを埋め込んでおいて、その情報をWiresharkで参照する必要があります。wolfSSLライブラリのほうもそのためのオプションを指定してビルドする必要があります。
wolfSSLのダウンロード、ビルド手順は "その1:鍵交換"で紹介した手順と基本的に同じですが、上記オプション指定を追加します。
$ git clone https://github.com/wolfssl/wolfssl
$ cd wolfssl
$ ./autogen.sh
$ ./configure --with-liboqs CFLAGS="-DHAVE_SECRET_CALLBACK"
$ make all
$ sudo make install
サンプルプロラムのビルドも同様のオプションを追加します。
$ cd wolfssl-examples/pq
$ make CFLAGS="-DHAVE_SECRET_CALLBACK"
4.4 TLSハンドシェークを見てみる
次に、サンプルサーバとクライアントを動作させてTLSハンドシェークのほうを見てみることにします。サンプルはwolfssl-examples/pq/server-pq-tls13.cとclient-pq-tls13.cを使います。
サンプルクライアント(client-pq-tls13.c) のソースコードを見ると、下のようにデフォルトの証明書パスが定義され、それがロードされていることがわかります。それ以外の部分は普通のTLSクライアントです。サーバ側(server-pq-tls13.c)もほぼ同様です。
#define CERT_FILE "../certs/falcon_level5_root_cert.pem"
char *cert_file = CERT_FILE;
/* 証明書のロード */
if ((ret = wolfSSL_CTX_load_verify_locations(ctx, cert_file, NULL))
Wireshark を立ち上げて、サンプルサーバを起動します。
$ ./server-pq-tls13
次にクライアント側を起動し、サーバに送るメッセージを入力します。
$ ./client-pq-tls13 127.0.0.1
Message for server: Hello Server
Server: I hear ya fa shizzle!
その内容はサーバ側に表示されます。
Waiting for a connection...
Client connected successfully
Client: Hello Server
Waiting for a connection...
この状態でWireshakeを "Filter:tls" で見てみると、下のように"Server Hello" が暗号化された状態で表示されます。
No. Time Source Destination Protocol Length Info
889 10.059814 127.0.0.1 127.0.0.1 TLSv1.3 1990 Client Hello
891 10.078259 127.0.0.1 127.0.0.1 TLSv1.3 1820 Server Hello
893 10.078592 127.0.0.1 127.0.0.1 TLSv1.3 84 Application Data
...
1447 19.384021 127.0.0.1 127.0.0.1 TLSv1.3 91 Application Data
1449 19.384158 127.0.0.1 127.0.0.1 TLSv1.3 100 Application Data
1451 19.384188 127.0.0.1 127.0.0.1 TLSv1.3 80 Application Data
この時、サンプルプログラムを起動したディレクトリの直下に "sslkeylog.log" という名前でセッション鍵情報のファイルが生成されているはずです。Wirehsarkの設定→プロトコル→TLS→"(Pre)-Master-Secret log file name"でこのファイル名を指定すると下のように各メッセージが復号されて表示され普通のTLS1.3のハンドシェークであることがわかります。
No. Time Source Destination Protocol Length Info
889 10.059814 127.0.0.1 127.0.0.1 TLSv1.3 1990 Client Hello
891 10.078259 127.0.0.1 127.0.0.1 TLSv1.3 1820 Server Hello
893 10.078592 127.0.0.1 127.0.0.1 TLSv1.3 84 Encrypted Extensions
895 10.078722 127.0.0.1 127.0.0.1 TLSv1.3 3871 Certificate
897 10.079683 127.0.0.1 127.0.0.1 TLSv1.3 1358 Certificate Verify
899 10.080004 127.0.0.1 127.0.0.1 TLSv1.3 114 Finished
901 10.087176 127.0.0.1 127.0.0.1 TLSv1.3 114 Finished
903 10.087343 127.0.0.1 127.0.0.1 TLSv1.3 238 New Session Ticket
1447 19.384021 127.0.0.1 127.0.0.1 TLSv1.3 91 Application Data
1449 19.384158 127.0.0.1 127.0.0.1 TLSv1.3 100 Application Data
1451 19.384188 127.0.0.1 127.0.0.1 TLSv1.3 80 Alert (Level: Warning, Description: Close Notify)
まずは、 "Client Hello" の内容をみてみます。"Signature Algorithms" の "Signature Hash Algorithms" を見てみると "Unknown Unknown (0xfe0b)" のように生のID値が示されてりるものが二つほどあるのがわかります。wolfSSLのこのバージョンでサポートしているFalcon Level1 とLevel5なのですが、通常版のWiresharkではまだこれらのアルゴリズムのシンボル表示に対応していないのでこのように表示されます。(こちらのパッチで内容を表示することもできます。)
Handshake Protocol: Client Hello
...
Extension: signature_algorithms (len=36)
Type: signature_algorithms (13)
Length: 36
Signature Hash Algorithms Length: 34
Signature Hash Algorithms (17 algorithms)
Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603)
...
Signature Algorithm: Unknown Unknown (0xfe0b) <--- Falcon Level 1
Signature Algorithm: Unknown Unknown (0xfe0e) <--- Falcon Level 5
...
次に、"Certificate" の内容を見てみると、Signature 、subjectPublicKeyのAlgorithm IDとしてiso.3.9999.3.4とFalconに対応する生のID値が表示されているのがわかります。
Handshake Type: Certificate (11)
Length: 3789
Certificate Request Context Length: 0
Certificates Length: 3785
Certificates (3785 bytes)
Certificate Length: 3780
Certificate: 30820ec0308209baa00302010202020401300706052bce0f0304308196310b3009060355…
signedCertificate
version: v3 (2)
serialNumber: 0x0401
signature (iso.3.9999.3.4)
Algorithm Id: 1.3.9999.3.4 (iso.3.9999.3.4)
...
subjectPublicKey:
0a4b323a9b7f054c1d518c50dfd2ee85f8f3c2b70b3a29847e28a9658f034c227acf2150…
extensions: 6 items
algorithmIdentifier (iso.3.9999.3.4)
Algorithm Id: 1.3.9999.3.4 (iso.3.9999.3.4)
Padding: 0
encrypted: 3ac3fcf54764f8a90c3e390bb76f1bbc0f501b6b5ea20ba39d0eda45b38d3a7baf2c2854…
Extensions Length: 0
サンプルのサーバ、クライアントは次のようにオプションアーギュメントでファイル名を指定できるようになっているので、certsディレクトリ下のその他のサンプルファイルやその他のファイルで試すこともできます。
$ ./server-pq-tls13 [<サーバ証明書> <プライベート鍵>]
$ ./client-pq-tls13 IPアドレス [<CA証明書>]
5. まとめ
この記事では、ポスト量子暗号によるTLSプロトコルのうち署名部分ついてみてきました。記事中にもコメントしたように、従来のRSAやECCによる署名にくらべて署名サイズはかなり大きなものになってしまう点でアルゴリズムにはまだまだ改善の余地があるようにも感じられます。しかし、現時点でTLSの枠組みののなかでまがりなりにも実際に使用できるアルゴリズムができあがりつつあることが感じられるかと思います。