/note/tech

The State of OpenSSL for pyca/cryptography

要約:

■ 1. 記事の概要

  • pyca/cryptography(Pythonの暗号化ライブラリ)のメンテナーであるPaul KehrerとAlex Gaynorによる2026年1月14日の記事
  • 12年間OpenSSLに依存してきたが成長する問題について2025年10月のOpenSSL Conferenceで発表
  • OpenSSLの開発における過ちが重大になったため実質的な変更が必要(OpenSSLに対して、または依存関係に対して)

■ 2. OpenSSLの軌跡(3幕構成)

  • 第1幕: Heartbleed以前(2014年以前):
    • OpenSSLはメンテナンスが不十分で停滞していた
    • 期待を大幅に下回っていた
  • 第2幕: Heartbleed直後:
    • OpenSSLのメンテナンスが再活性化され大幅な進歩と改善
    • 実際のコードレビュープロセスの導入
    • CIでのテスト実行開始
    • ファジングテストの採用
    • リリースプロセスの成熟
  • 第3幕: 2021年のOpenSSL 3リリース:
    • 新しいAPIを導入し大規模な内部リファクタリング
    • パフォーマンス/複雑性/APIの使いやすさにおいて大幅な後退
    • テスト/検証/メモリ安全性の面で必要な改善がなかった
    • 同時期にOpenSSLのフォーク(LibreSSL/BoringSSL/AWS-LC)はこれらの分野で進歩

■ 3. パフォーマンスの問題

  • OpenSSL 1.1.1と比較してOpenSSL 3はパース処理やキー読み込みなどで大幅なパフォーマンス後退
  • 楕円曲線公開鍵の読み込みがOpenSSL 1.1.1と3.0.7の間で5〜8倍遅くなった
  • 改善後も以前より3倍遅い
  • OpenSSLの対応は「OpenSSL 3では後退が予想されており最適化の余地はあるが1.1.1レベルに戻ることは期待すべきではない」
  • pyca/cryptographyがX.509証明書パースをOpenSSLから独自のRustコードに移行した結果OpenSSL 3と比較して10倍のパフォーマンス向上
  • 公開鍵パースを独自のRustコードに移行したことでエンドツーエンドのX.509パス検証が60%高速化
  • 独自パースでより良いパフォーマンスを達成できることは実践的に可能であることを示している
  • 彼らのパフォーマンスは巧妙なSIMDマイクロ最適化の結果ではなくコピー/アロケーション/ハッシュテーブル/間接呼び出し/ロックを避けるというシンプルな方法の結果

■ 4. 複雑性とAPIの問題

  • OpenSSL 3はAPIを大幅に変更し始めた
  • OSSL_PARAMを導入しすべての新しいAPIサーフェスに使用(ポスト量子暗号アルゴリズムを含む)
  • OSSL_PARAMは通常の引数渡しの代わりにキー値ペアの配列を関数に渡す
  • OSSL_PARAMの問題点:
    • パフォーマンス低下
    • コンパイル時検証の減少
    • 冗長性の増加
    • コードの可読性低下
  • 具体的な比較:
    • OpenSSLでML-KEMカプセル化を行うには37行と6つのフェイラブル関数呼び出しが必要
    • BoringSSLでは19行と3つのフェイラブル関数呼び出し
  • OpenSSL内部も複雑化:
    • OSSL_PARAMの配列管理を容易にするために多くのソースファイルがCファイルではなくCコード用のカスタムPerlプリプロセッサを持つ
  • OpenSSL 3は「providers」の概念を導入:
    • アルゴリズムの外部実装を許可
    • プログラム実行の任意の時点で任意のアルゴリズムを置き換えることを許可
    • ほぼすべての操作に無数のアロケーションとロックを追加する必要があった
    • パフォーマンス後退の原因
  • 悪い決定の連鎖:
    • providersAPIの設計ミス → パフォーマンス後退 → キャッシングとRCUによる追加の複雑性 → さらなるバグ → それでもパフォーマンスは最初より悪い
  • OpenSSLのソースコードを読むことが苦痛になった:
    • 間接呼び出し/オプションパス/#ifdef/その他の理解への障害の数が驚くべきもの
    • 以前はそうではなかったしLibreSSL/BoringSSL/AWS-LCでもそうではない

■ 5. テストと検証の問題

  • OpenSSLプロジェクトはテストを十分に優先していない
  • OpenSSL 3.0開発サイクル中にテストカバレッジのギャップが顕著に見えた:
    • 16ヶ月にわたる19のプレリリースの拡張アルファ/ベータ期間中にコミュニティからの後退報告に大きく依存
    • 自社テストでは意図しない実世界の破損をキャッチするには不十分だった
  • バグ修正が付随する回帰テストなしでランドされることがまだ一般的
  • OpenSSLのCIは非常にフレーキー(不安定)でプロジェクトはこのフレーキーさを許容するようになった
  • OpenSSL 3.0.4の重大なバグの例:
    • AVX-512対応CPUでのRSA実装に重大なバッファオーバーフロー
    • CIで実際にキャッチされていたがCIランナーがたまたまAVX-512 CPUを持っている場合にのみクラッシュが発生したため障害はフレーキーさとして却下された
  • 3年後もテストが失敗するコードをマージ:
    • カンファレンススライド準備日には最近の10コミット中5つがCIチェック失敗
    • トーク前日にはすべてのコミットがクロスコンパイルビルド失敗
  • Intel SDEなどのツール採用の価値:
    • x86-64拡張命令の異なるサブセットを持つCPUに対する制御されたテストが可能
    • AVX-512の有無での専用テストジョブを持つことで障害の性質がすぐに読みやすく再現可能になる
  • OpenSSLは形式検証の最先端に追いついていない:
    • 形式的手法は学術的な新奇さから暗号コードの意味のある部分に対する実用的な現実になった
    • BoringSSLとAWS-LCは形式的に検証された実装を組み込み自動推論を使用して保証を高めている

■ 6. メモリ安全性の問題

  • OpenSSL作成時にはパフォーマンス/埋め込み可能性/メモリ安全性を意味のある形で提供するプログラミング言語はなかった
  • 世界は変わった:
    • 約5年前にpyca/cryptographyはRustコードを組み込んだ最初のリリースを発行
    • それ以来ほぼすべての機能をRustに移行
    • 純粋なRustですべてのパースとX.509操作を行い暗号アルゴリズムにはOpenSSLを使用
    • パフォーマンス向上と複数のOpenSSL CVEの回避を達成
  • これらの移行が可能であることを彼らは知っている
  • セキュリティにコミットしたライブラリはメモリ安全なプログラミング言語への長期的な移行にコミットする必要がある
  • OpenSSLはこの問題に全くイニシアチブを示していない

■ 7. 原因の考察

  • これは資金不足やコモンズの悲劇の問題ではない
  • Heartbleed以降の10年間でOpenSSLはかなりの資金を受け取っている
  • 現時点でOpenSSL CorporationとFoundationはBoringSSLまたはLibreSSLでフルタイムで働く人数より多くのソフトウェアエンジニアを雇用
  • 他のOpenSSLフォークがこれらの同じ設計選択をしていないという事実は「これが必要だったか」という質問に対して有益な情報

■ 8. 今後の方向性

  • ポリシー変更1:
    • 新機能にOpenSSL実装を要求しない
    • LibreSSL/BoringSSL/AWS-LCでのみ利用可能な新しいAPIを追加
    • 具体的にはML-KEMとML-DSA APIをLibreSSL/BoringSSL/AWS-LCでのみ利用可能にしOpenSSLでは利用不可
  • ポリシー変更2:
    • 現在wheelsにOpenSSLのコピーを静的リンクしている
    • wheelsをOpenSSLフォークの1つにリンクするために何が必要かを調査開始
  • ポリシー変更3:
    • バイナリwheelsをOpenSSLフォークの1つに切り替えることに成功した場合OpenSSLのサポートを完全に廃止する状況の検討を開始
  • 長期的方向性:
    • GraviolaなどのOpenSSL派生でない暗号ライブラリを潜在的な代替として積極的に追跡
  • 暗号実装を提供するために使用するライブラリの変更はユーザー(特に再配布者)に大きな影響を与えることを認識
  • これらのステップを軽々しく考えておらず急いで行うことも予想していない
  • 懸念の重大さから行動せざるを得ない
  • pyca/cryptographyのOpenSSLサポートに依存している場合はOpenSSLプロジェクトに関与しこれらの軸での改善に貢献することが最も抜本的なステップを避ける最良の方法