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

Go Proposal Weekly Digest

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

#77704active

x/crypto/acme: support standards compliant order finalization

新規提案

要約

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

概要

x/crypto/acme パッケージにおいて、ACME(RFC 8555)の証明書発行フロー(Order Finalization)を仕様準拠の方法で実行できる新APIを追加する提案です。既存の CreateOrderCert が一部CAの非標準的な挙動に依存している問題を解消します。

ステータス変更

**(新規)active
2026-08-20の提案レビュー会議で active カラムに追加され、今後は毎週のレビュー会議で継続的に議論されることになりました。提案者(cpu、Let's Encrypt/Boulder関連の知見を持つ人物)による初期提案と、それに対するコアチーム(neild)からのフィードバックを経て、API名についてほぼ合意が得られた段階での「active」入りです。

技術的背景

現状の問題点

x/crypto/acmeClient.CreateOrderCert は、finalization URL(文字列)のみを引数に取り、CSR(証明書署名要求)をそのURLにPOSTします。しかしRFC 8555の仕様上、finalizeレスポンスに Location ヘッダーが含まれることは保証されていません(実際、RFC 8555 §7.4の「typical sequence of requests」表でも finalize order のアクションには Location を示す -> が付いていません)。
にもかかわらず、Let's EncryptのCA実装であるBoulderがこのヘッダーを常に返していたため、x/crypto/acme はそれに依存する実装になってしまっていました。ACMEのテストサーバーであるPebbleが最近この非標準ヘッダーを意図的に削除したことで(pebble#509)、Pebbleの新バージョンとの統合テストが失敗するようになり、さらにBuypassのような一部のCAでは元々このヘッダーを返していないため、x/crypto/acme が仕様準拠のCAと相互運用できないという実問題が顕在化しました。

提案された解決策

後方互換性を保つため既存の CreateOrderCert はそのまま残しつつ、Godocに「このメソッドはfinalizationレスポンスに Location ヘッダーを返すCAでのみ動作する」旨の警告を追記します。
その上で、新メソッド CreateCertFromOrder(ctx, order *Order, csr []byte, bundle bool) を追加します。これはURL文字列の代わりに AuthorizeOrder() で生成済みの *Order を受け取り、内部的には Order.FinalizeURL をfinalization POST先として使い、Order.URI(Order作成時のレスポンスの Location ヘッダーから取得され、こちらはRFC 8555で保証されている)をポーリング対象URLとして使います。これにより Location ヘッダーへの依存を finalization レスポンスからorder作成レスポンスへ移すことができ、仕様準拠のCAでも正しく動作するようになります。
なおメソッド名については議論の末、CreateCertForOrderCreateCertWithOrder などの候補から、finalizationがOrderに対する「終端操作」であることを表す CreateCertFromOrder が有力案としてまとまりました。

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

これまでBoulder(Let's Encrypt)以外のRFC 8555準拠CA(例: Buypass)を使う場合に発生していた「finalization後のポーリングが空URLへのPOST-as-GETで失敗する」という問題を回避できます。ACMEクライアントの相互運用性が向上し、Pebbleの新バージョンを使ったテストや、Boulder以外のCA実装を利用する開発者にとってメリットがあります。

コード例

// Before: CreateOrderCert はURL文字列を渡すため、
// finalizeレスポンスにLocationヘッダーがないCAでは失敗する
order, err := client.AuthorizeOrder(ctx, ids)
// ...
der, certURL, err := client.CreateOrderCert(ctx, order.FinalizeURL, csr, true)
// -> finalizeレスポンスにLocationがないCAでは、
//    内部で order.URI が "" になりポーリングが失敗する
// After: CreateCertFromOrder は *Order を直接渡すため、
// AuthorizeOrder時に取得済みの order.URI (Location準拠) を使ってポーリングできる
order, err := client.AuthorizeOrder(ctx, ids)
// ...
der, certURL, err := client.CreateCertFromOrder(ctx, order, csr, true)

議論のハイライト

  • 提案の技術的な内容自体には大きな異論は出ず、議論の中心はもっぱら新メソッドの命名でした。CreateCertForOrderCreateCertWithOrderCreateCertFromOrder が候補に挙がりました。
  • neild(コアチーム)は「名前がやや分かりにくいが、他に良い案も見当たらない」とコメントしつつ、提案自体はおおむね妥当と評価しました。
  • 提案者cpuは、finalizationがOrderに対する不可逆な終端操作である点(一度finalizeしたOrderから再度別の証明書を作ることはできない)を理由に From を推し、これが有力案としてまとまりました。
  • 既存の CreateOrderCert は後方互換性のため削除せず維持しつつ、Godocに非推奨的な注意書き(RFC 8555準拠CAでは CreateCertFromOrder を推奨する旨)を追加する方針が確認されました。
  • 提案者は autocert パッケージ内の CreateOrderCert 呼び出し箇所はすべて手元に *Order があるため、問題なく新APIへ移行できると述べています。
  • 実装CL(go.dev/cl/817000)がすでに提出されており、議論と並行して実装が進んでいます。

関連リンク