crl_override (and extensions) in /api/v1/sign request body are silently ignored by the HTTP API
メンテナーはふだん 3 日以内に返信
評価
調査の方向性
api/signhandler/signhandler.go から始め、jsonSignRequest を jsonReqToTrue() を通じて追跡し、その後 HTTP パスを signer/local/local.go と比較します。提供されている curl コマンドを使ってリクエストを再現し、openssl で証明書を調べます。crl_override と extensions が両方の API 署名パスを通じて保持され、結果の証明書に要求した拡張が現れれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Version: 1.6.5 (also present on master as of this writing) · Go 1.20.14
Summary
signer.SignRequest defines a CRLOverride field (JSON tag crl_override) that the local signer honors to set a per-request CRL Distribution Point. However, when signing through the HTTP /api/v1/sign (and /api/v1/authsign) API, the field is silently dropped. The issued certificate contains no CRL Distribution Points extension (2.5.29.31), and no error or warning is returned. The same applies to the extensions field.
Expected behavior
Posting crl_override to /api/v1/sign embeds a CRLDistributionPoints (2.5.29.31) extension in the issued certificate, matching the behavior of the local signer library and the documented SignRequest schema.
Actual behavior
The request succeeds, but the returned certificate has no 2.5.29.31 extension. crl_override is accepted (no validation error) yet has no effect.
Root cause
The HTTP handler does not unmarshal the body into signer.SignRequest. It uses an intermediate jsonSignRequest struct, then jsonReqToTrue() copies only a fixed subset of fields into the real SignRequest. Neither crl_override nor extensions is part of that struct or the copy:
api/signhandler/signhandler.go:
// This type is meant to be unmarshalled from JSON so that there can be a
// hostname field in the API
// TODO: Change the API such that the normal struct can be used.
type jsonSignRequest struct {
Hostname string `json:"hostname"`
Hosts []string `json:"hosts"`
Request string `json:"certificate_request"`
Subject *signer.Subject `json:"subject,omitempty"`
Profile string `json:"profile"`
Label string `json:"label"`
Serial *big.Int `json:"serial,omitempty"`
Bundle bool `json:"bundle"`
}
func jsonReqToTrue(js jsonSignRequest) signer.SignRequest {
// ... never sets CRLOverride or Extensions ...
return signer.SignRequest{
Hosts: js.Hosts,
Subject: sub,
Request: js.Request,
Profile: js.Profile,
Label: js.Label,
Serial: js.Serial,
}
}
By contrast, signer/local/local.go does honor CRLOverride (so it works when CFSSL is used as a Go library), which makes the API behavior surprising:
if req.CRLOverride != "" {
safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
}
// ... preserved across FillTemplate via save/restore of distPoints ...
The existing TODO: Change the API such that the normal struct can be used. comment acknowledges this divergence.
Steps to reproduce
Run a CFSSL server with any signing profile (no crl_url set in config.json):
cfssl serve -address 0.0.0.0 -port 8888 -ca ca.pem -ca-key ca-key.pem -config config.json
Sign a CSR via the HTTP API with crl_override:
curl -s http://localhost:8888/api/v1/cfssl/sign -d '{
"certificate_request": "'"$(awk 'NF {sub(/\r/,""); printf "%s\\n",$0}' test.csr)"'",
"crl_override": "http://example.com/my.crl"
}' | jq -r '.result.certificate' > out.pem
Inspect the issued certificate:
openssl x509 -in out.pem -noout -text | grep -A2 "CRL Distribution"
# (no output — extension is absent)
Observed: no X509v3 CRL Distribution Points in the certificate.
Expected: the extension present with URI http://example.com/my.crl.
Workaround
Set crl_url in the signing profile (config.json), which FillTemplate applies server-side:
{ "signing": { "default": { "crl_url": "http://example.com/my.crl", "expiry": "8760h", "usages": ["signing","server auth"] } } }
This works but is static per-profile and cannot vary per request.
Suggested fix
Add CRLOverride string \json:"crl_override"(andExtensions) to jsonSignRequestand copy them in both branches ofjsonReqToTrue(), or follow the existing TODO and unmarshal directly into signer.SignRequest. Alternatively, if per-request override is intentionally unsupported over HTTP, document it and return a validation error when these fields are supplied.
- 主要言語
- Go
- スター
- 9.5k
- フォーク
- 1.2k
- 平均マージ
- 8日 2時間
- マージ済み PR(30日)
- 3
環境構築
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
cloudflare/cfssl のほかの issue
-
gencrl: serial numbers that fail to parse are added to the CRL as 0 or a partial value対応中かも @sebxt が 17 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
cloudflare/cfssl#1460 ·
メンテナーはふだん 3 日以内に返信
-
gencrl silently revokes the wrong serial number when a line is not plain decimal対応中かも @RaphaelFakhri が 18 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 30/100
cloudflare/cfssl#1458 ·
メンテナーはふだん 3 日以内に返信
-
config: LoadConfig panics when not_after is before not_before対応中かも @sebxt が 19 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 25/100
cloudflare/cfssl#1456 ·
メンテナーはふだん 3 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 48/100
cloudflare/cfssl#1446 ·
メンテナーはふだん 3 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
cloudflare/cfssl#1443 · コメント 4 件 ·
メンテナーはふだん 3 日以内に返信
cloudflare/cfssl の issue をすべて見る
似ている issue
-
Query cache: a failed cache page read leaves the set request's read lock held, so the scan hangsオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
turbot/steampipe-plugin-sdk#986 · コメント 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
router-for-me/CLIProxyAPI#7307 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
betterleaks/betterleaks#460 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
openmcp-project/service-provider-crossplane#330 ·
メンテナーはふだん 1 日以内に返信