メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#77431active

encoding/asn1,crypto/x509: consider allowing lax parsing mode

新規提案

要約

AIによる要約であり、誤りを含む場合があります。

概要

encoding/asn1crypto/x509が採用している厳格なASN.1パース規則により、規格上は不正だが実際に広く流通してしまっている証明書(PrintableStringにアンダースコア_を含む等)を読み込めないという問題に対し、緩い(lax)パースモードを設けることを検討するproposalです。

ステータス変更

**(未設定/新規)active
提案がGoチームのproposal reviewキューの「active」列に追加され、今後は週次のproposal reviewミーティングで継続的に議論・レビューされる段階に入りました。まだ具体的なAPI設計は固まっておらず、GODEBUGフラグ案・新関数案・グローバルAPI案など複数の実装アプローチが比較検討されている段階です。

技術的背景

現状の問題点

Goのencoding/asn1crypto/x509パーサーは仕様に忠実で、たとえばPrintableString型はASCII文字全体を技術的には保持できるものの、ASN.1仕様が許可する文字集合はより限定的(アンダースコア_などは非許可)です。しかし現実には、この制約を守らない実装で発行された証明書が、特にIoTデバイスや組み込み機器のファームウェアに焼き込まれる形で大量に流通しています。こうした証明書はハードウェア的な制約により再発行・更新が困難で、Goの厳格なパーサーではx509: invalid RDNSequence: invalid attribute value: invalid PrintableStringのようなエラーで読み込みそのものが失敗してしまいます。

// 現状: PrintableStringにアンダースコアが含まれる証明書はパースエラーになる
cert, err := x509.ParseCertificate(der)
// err: x509: invalid RDNSequence: invalid attribute value: invalid PrintableString

提案された解決策

提案当初はGODEBUG=laxasn1parsing=[a-z]+(,[a-z])*のように、個々の検証ルールを名前指定で無効化できる環境変数を導入する案でした。最初に無効化対象となるのは文字列型の文字種チェック(PrintableStringの許容文字範囲など)です。
ただし、レビュー会議では以下の代替案が挙がっています。

  • GODEBUGによる制御は「あまり好まれない」との反応(パース処理はcrypto/tlsなど深い層に埋め込まれていることが多く、呼び出しごとにオプションを渡すのが難しいため)。
  • 代わりにグローバルな設定をAPI経由で明示的に切り替える方式。
  • 緩和対象をencoding/asn1全体ではなくcrypto/x509にスコープを絞る案。
  • パーサーが証明書本体とエラー(複数)の両方を返し、呼び出し側でどのエラーを許容するか判断させる案。

これによって何ができるようになるか

現行では規格違反の証明書は一切パースできず、OpenSSLやJavaのcrypto実装では読める証明書がGoだけ読めない、という互換性問題が起きています。この提案が実現すれば、以下のようなケースで役立ちます。

  • IoT機器の製造時に組み込まれた、修正不能なデバイス証明書の読み込み(セキュアクリプトプロセッサに焼き込まれ、デバイス寿命分使い続けるもの)
  • 車載機器メーカーなど大手ベンダーが発行する、長年にわたり規格違反が是正されない証明書の相互運用
  • 現在ソースコードにパッチを当てて(例: evcc.ioプロジェクトの独自パッチ)運用している既存の回避策の標準サポート化

コード例

// Before: 標準ライブラリのソースにパッチを当てて回避する、または自前でASN.1パーサーを実装する
// (現状ワークアラウンドの例、evcc.ioのようなアプローチ)
// diffで検証ロジックを削除するなど、標準ライブラリを改変
// After: 議論中の案の一つ(イメージ)。API経由でlaxモードを明示的に有効化
cert, err := x509.ParseCertificateLax(der) // 案の一つ、まだ確定していない
// あるいは、証明書と検証エラー一覧の両方を返す方式
cert, errs := x509.ParseCertificateWithErrors(der)
if allowedErrors(errs) {
    // アプリケーション側で許容可能なエラーか判断して利用継続
}

※上記は議論中の設計案を示すための仮のコードであり、確定したAPIシグネチャではありません。

議論のハイライト

  • コミュニティからは、GODEBUGよりも明示的な関数(例: ParseLax)やグローバル設定APIを望む声が上がった(@earthboundkidの指摘に3件の賛同)。
  • IoT/組み込み業界のユーザーから、デバイス証明書がハードウェアに焼き込まれ更新不能であるため、この機能が「必須」であるとの強い要望が複数寄せられた。
  • レビュー会議では、パース処理がcrypto/tlsなど深い層に隠蔽されているため、呼び出しごとのオプション渡しは現実的でなく、グローバル設定またはAPIベースの制御が有力視されている。
  • 緩和対象をencoding/asn1全体でなくcrypto/x509にスコープを絞る案、および特定の既知の壊れた証明書のみを許可リスト化する案が代替案として検討された。
  • 「証明書本体と検証エラーの両方を返す」案が有望視される一方、既存の深い層のAPI(crypto/tls等)も合わせて変更する必要があるという課題が指摘され、依然として設計は流動的である。
  • 類似の先行proposal #70324(crypto/x509向けのlaxフラグ)はクローズ済みで、本issueはそれを踏まえた再提案という位置づけ。

関連リンク