| Ticket Hash: | d78258f03ba7693307cc3c1f936ae71f79477a0f | ||
| Title: | BusyBox wget fails on every HTTPS URL: LibreSSL s_client has no -verify_hostname | ||
| Status: | Review | Type: | Code_Defect |
| Severity: | Important | Priority: | High |
| Subsystem: | seed | Resolution: | |
| Last Modified: |
2026-11-04 18:12:12 6.5 days ago |
Created: |
2026-11-04 13:40:43 6.7 days ago |
| Version Found In: | 1.0.0 | ||
| Description: | ||||
|
Reported by cleave's x86-1 session, which can't file here: https://ollama.openbeagle.org/cleave/forumpost/c00b940ecc. The maintainer asked for a ticket and a fix. This is F1 on the log ticket 2a8699a249, whose cause had not been found.
CAUSE (checked in BQ2 run 7166acba21's root filesystem, x86_64, the 1.0.0 seed plus an overlay, 2026-11-04) - BusyBox 1.36.1's wget (networking/wget.c, spawn_https_helper_openssl) fetches https URLs by running: openssl s_client -quiet -connect HOST:PORT -servername HOST -verify 100 -verify_return_error -verify_hostname HOST. With an IP address, it passes -verify_ip instead. - The seed's openssl is LibreSSL 3.8.2, whose s_client rejects that option: "unknown option -verify_hostname". BusyBox sends s_client's stderr to /dev/null, so wget reports only "error getting response: Connection reset by peer". - Reproduced: busybox wget -q -O /dev/null https://www.example.com/ exits 1. WHY DROPPING THE OPTION IS NOT ENOUGH - LibreSSL's s_client has no hostname check at all. These were tested with -servername HOST -verify 100 -verify_return_error: - wrong.host.badssl.com passes (exit 0); - expired.badssl.com fails (exit 1). - So without -verify_hostname, wget would accept any valid certificate for the wrong host. - No LibreSSL release adds the option: the s_client.c of 3.9.2, 4.0.0 and 4.1.0 has no verify_hostname. Upgrading doesn't fix it. - BusyBox's other HTTPS path, its internal TLS (FEATURE_WGET_HTTPS), checks no certificate at all. FIX OPTIONS (not chosen yet) A. A small BQ2 helper that verifies the hostname. A bq2 applet takes the same arguments and pipes stdin and stdout over a TLS connection made with Crystal's OpenSSL::SSL::Context::Client, which checks the chain and the hostname by default. A one-line BusyBox patch makes wget run it instead of openssl s_client. This keeps verification complete, and follows "Crystal over shell". Alpine solves the same problem the same way, with a small libtls ssl_client. B. A BusyBox patch that leaves out -verify_hostname and -verify_ip. It is smallest and makes wget work, but it loses the hostname check, as shown above. C. Drop wget from the tool contract and point people to curl. This doesn't help glint, whose tools/c_archive_build.cr runs busybox wget on https URLs. DONE-WHEN - A seed rebuilt with the fix runs busybox wget against https://www.example.com/ and exits 0, and fails against https://wrong.host.badssl.com/ and https://expired.badssl.com/. - A sysroot-functest case covers it, run only with network, as the curl/wget contract row says. | ||||
| User Comments: | ||||
added on 2026-11-04 13:45:43:
FIX (option A), 8:45 AM, Wednesday, November 4 Detroit time: check-in https://ollama.openbeagle.org/bootstrap-qcow2/info/ee75b652a0 on branch seed-ocx-links, not merged to trunk. - New bq2 applet: tls-connect [--insecure] HOST:PORT NAME. It verifies the chain and the name with Crystal's TLS client, then pipes stdin and stdout over the connection. - The BusyBox patch wget-use-bq2-tls-connect.patch makes wget run it, and leaves stderr open, so a refusal now says "certificate verify failed". - Tested here with a hand-built patched BusyBox: - example.com, 1.1.1.1 and a GitHub tarball through a redirect all succeed; the tarball is byte-identical to upstream; - wrong.host, expired and self-signed .badssl.com are refused; - --no-check-certificate still connects. - Status Review: the done-when still needs a rebuilt seed and a network-only sysroot-functest case. added on 2026-11-04 18:12:12: Verified on a rebuilt aarch64 seed (aarch64-1, run 0de68bf272, seed-ocx-links ee75b652a0, seed sha256 ed8e173a6b2c...): wget https works for good hosts and a GitHub redirect (byte-identical to curl); wrong.host, expired and self-signed badssl.com are refused with 'certificate verify failed'; --no-check-certificate connects. Control: the trunk 1.0.0 aarch64 seed resets every verified https fetch. Cosmetic: wget still adds 'error getting response: Connection reset by peer' after the real error. 1:12 PM, Wednesday, November 4 (Detroit). | ||||