TLS 1.3 のテスト用に公開されているNSSサーバは2つあります。
Haskell TLS 1.3 client では、前者とフルハンドシェイクできるのですが、後者は handshake error を返してきます。一方で、Firefox Nightly や Chrome Canary は、後者に問題なくアクセスできます。
必要な拡張が足らないのかと思い、Firefox Nightly が付けている拡張をすべて付けてみたりしましたがダメでした。この相互接続性は長い間の課題だったのですが、他の作業が落ち着いたこともあり、重い腰を上げて真面目に解析してみました。
採った方法は、Firefox Nightlyが出力する Client Hello のバイト列をそのまま送りつけるユーティリティを作り、徐々に拡張などを削っていて、handshake error を返す要因を特定することです。
驚くべきことにTLS 1.3に関係のない拡張を全部削除しても、tls13はServer Hello を返してきました。そこで、TLS 1.3に必須の拡張から値を徐々に消していきました。そして、Signature Scheme から ecdsa_secp384r1_sha384 を消したときに、handshake error になることを突き止めました。
tls13のサーバ証明書は ECDSAだったのです!同じ NSSサーバでも、franziskuskieferではうまくいくのに tls13ではうまくいかない理由が氷解しました。そこで、Haskell TLS 1.3 にECDSAのコードを入れたところ、めでたく tls13とハンドシェクできるようになりました。
NSSサーバは、NewSessionTicketを送ってきませんので、PSKハンドシェイクなどはできないようです。
追記:
Mozillaの人達と話したら、tls13 が NewSessionTicket を返さないのは、現在のNSSの実装では、ECDSA の証明書に対しそれを返せないからだそうです。証明書を RSA に変えて、NewSessionTicket を有効にしていただきました。めでたく、NewSessionTicket は届くようになりましたが、まだ PSK のハンドシェイクに成功していません。
これは mod_nss の問題のようです。ローカルでビルドした NSS とは、4つのハンドシェイク全部でつながることを確認できました。