Skip to content

feat(windows): build curl against OpenSSL instead of Schannel - #1

Merged
pjcdawkins merged 4 commits into
mainfrom
feat/windows-curl-openssl
Jul 30, 2026
Merged

feat(windows): build curl against OpenSSL instead of Schannel#1
pjcdawkins merged 4 commits into
mainfrom
feat/windows-curl-openssl

Conversation

@pjcdawkins

Copy link
Copy Markdown
Contributor

Builds curl against OpenSSL instead of Schannel on Windows, so that the CLI can trust a root certificate installed by an organization. Related to upsun/cli#110.

Why

Schannel verifies against a CA file instead of the Windows certificate store: given a file, it builds a chain engine whose only trust anchors are that file's certificates. It also refuses a CA file larger than 1 MiB (MAX_CAFILE_SIZE in curl's schannel_verify.c).

The CLI has to pass a CA file, because the openssl extension cannot read the store at all and the CLI uses openssl streams for some requests. So on Windows the CLI trusts only the certificates shipped with it, and a machine whose TLS traffic is inspected — where every other program trusts the organization's root certificate from the store — fails with cURL error 60.

This was measured on a Windows runner rather than inferred. With a CA installed in the machine's root store and a server signed by it:

PHP configuration result
no CA file trusted, the store is used
openssl.cafile set to the shipped bundle ERR:60:schannel: the certificate or certificate chain is based on an untrusted root
openssl.cafile set to the shipped bundle plus the store's certificates trusted
the whole store merged into the bundle (467 certificates, 758 KB) ERR:77:schannel: CA file exceeds max size of 1048576 bytes

curl built against OpenSSL loads a CA file and the Windows stores together (lib/vtls/openssl.c, ossl_windows_load_anchors, reported as "Native: Windows System Stores ROOT+CA"), and no backend other than Schannel caps the file size. OpenSSL is already built here, for the openssl extension.

What changed

scripts/patch-spc-windows-curl.php patches the static-php-cli checkout before the build:

  • flips CURL_USE_SCHANNEL / USE_WINDOWS_SSPI off and CURL_USE_OPENSSL on
  • adds openssl back to curl's Windows dependencies in config/lib.json, so the build order puts it first

static-php-cli chose Schannel in crazywhalecc/static-php-cli#674 — "disable openssl due to certificate issue" — which is presumably that OpenSSL-built curl has no default CA bundle on Windows and so fails out of the box. That does not apply here, because the CLI always passes a bundle.

The script fails the build if static-php-cli no longer looks the way it expects, rather than quietly producing a Schannel build, which would reintroduce the bug silently. A new step then checks the backend of the binary that was actually built.

The Windows job now checks out this repository, which it did not need before.

Testing

The patch script was run against a clean static-php-cli 2.8.5 checkout: it makes the four expected changes and is idempotent. The build itself is what this PR is for — see the run on this branch.

Written by Claude Code.

Schannel verifies against a CA file instead of the Windows certificate
store, and refuses a file larger than 1 MiB. The CLI has to pass a CA
file, because the openssl extension cannot read the store at all, so a
root certificate installed by an organization is never trusted, and
requests fail with cURL error 60. curl built against OpenSSL loads a CA
file and the Windows stores together, and has no size limit. OpenSSL is
already built here for the openssl extension.

static-php-cli chose Schannel in its pull request 674, which also removed
OpenSSL from curl's Windows dependencies, so both are changed back. The
patch script fails the build if static-php-cli no longer looks the way it
expects, rather than quietly producing a Schannel build, and a new step
checks the backend of the binary that was built.

Related to upsun/cli#110

Written by Claude Code.
The windows-latest image now ships Visual Studio 2026, and
static-php-cli only looks for 2022 or 2019, so its doctor check fails
before anything is built. Nothing had been built since April, so this
went unnoticed.

Written by Claude Code.
The windows-2025 image ships Visual Studio 2026 as well, so pinning it
was not enough.

Written by Claude Code.
Schannel fell back to the Windows certificate store when curl was given
no CA file. OpenSSL does not, and CURL_CA_NATIVE is off by default, so
without this a request with no CA file would have no trust anchors at
all. curl only auto-enables the store when no CA file is set, so this
does not change the case where the CLI passes its bundle.

Written by Claude Code.
@pjcdawkins
pjcdawkins merged commit b10d255 into main Jul 30, 2026
14 checks passed
@pjcdawkins
pjcdawkins deleted the feat/windows-curl-openssl branch July 30, 2026 06:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant