cloudflare / cloudflare/cfssl

crl_override (and extensions) in /api/v1/sign request body are silently ignored by the HTTP API

Open
#1,439 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
9.5k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.