Repository navigation
fix(libSceHttp2): trust the host CA list for HTTPS requests - #33
Open
hypermoist wants to merge 5 commits into
Open
hypermoist wants to merge 5 commits into
hypermoist wants to merge 5 commits into
Conversation
…host CA roots Implement HTTP and HTTPS network transmission in libSceHttp2 using mbedTLS with root CA certificates loaded from the host OS rather than firmware. Both synchronous sceHttp2SendRequest and asynchronous sceHttp2SendRequestAsync execute real network requests and populate response status code, response headers, and response body. When the server responds with Transfer-Encoding: chunked, the body is decoded and sceHttp2GetResponseContentLength reports the decoded size with code 2. Assisted-by: Antigravity:gemini-3.8-flash
This was referenced Oct 27, 2026
Merged
added 4 commits
October 28, 2026 17:18
Take main's libSceHttp2 sources, which carry the HTTP/2 transport, in place of this branch's own transport in Export.cpp.
A request from a libSceSsl context that loads no certificate failed verification against every public server, so titles that rely on the default trust could not reach their services. libSceSsl gets SslTrustHostRoots_nid_no_patch, which makes one connection also trust /<sandbox word>/common/cert/CA_LIST.cer, the list libkernel serves from the host trust store (the system bundle on Linux, the ROOT store on Windows). The list is parsed once per process into its own pool and linked after the context's own authorities. A missing or certificate-free list adds nothing. The HTTP/2 transport calls it for every connection; verification stays on.
… were never created On a user profile where the current user's ROOT or Disallowed store has never been written, opening it with CERT_STORE_OPEN_EXISTING_FLAG fails with ERROR_FILE_NOT_FOUND, so the host CA list could not be built and every HTTPS request threw. Open the stores read-only without that flag; the system ROOT certificates are still enumerated through the user store.
The transport tests now read the host CA list, which libkernel caches under the working directory. Running them in one shared directory let parallel runs on Windows race on the cache file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This is #33 rebuilt on current
main, as the operator asked. It now sits on top of upstream's HTTP/2 transport (Transport.cpp, merged in #34) and adds only what still fails: trusting the host's CA roots for HTTPS.Cause on
main. Every libSceSsl context starts with no trust anchors. A title that loads no certificate and sets no verify callback (the usual case for a game talking to its publisher's public service) gets0x8095f00c(unknown CA) fromsceSslConnect. The transport then throwssceHttp2: TLS failed. Before the sync, the fork's offline stub returned0x80436063for this request instead. That code now only comes from the offlinesceHttp2SendRequestAsynccompletion added in #41, which never touches the network.Change.
SslTrustHostRoots_nid_no_patch(connection), declared inSsl.hpp. For one connection that has not started yet, it also trusts the host CA list/<sandbox word>/common/cert/CA_LIST.cer. libkernel already serves that file from the host trust store: the system bundle on Linux (SSL_CERT_FILE,/etc/ssl/certs/ca-certificates.crt,/etc/pki/tls/certs/ca-bundle.crt,/etc/ssl/ca-bundle.pem,/etc/ssl/cert.pem) and the ROOT store minus Disallowed on Windows, through CryptoAPI. So there is one host trust source and no second loader. Mbed TLS has no native-roots option of its own.sceSslInitpool. It is linked after the context's own authorities, so a title that loads its own CA keeps working.Transport.cppcalls the helper right aftersceSslCreateConnection. Verification stays on with the request's check flags. No host names, titles, stand-in servers or tokens.CERT_STORE_OPEN_EXISTING_FLAG. On a profile where the current user's store was never created, which is what happens under Wine, that flag made the open fail withERROR_FILE_NOT_FOUND, so no list could be built. Without the flag, the same profile lists 122 roots.guest_http2_transport*run gets its own working directory, because the CA list cache lives there and parallel Windows runs raced on it.Compared with the old #33. The second transport in
Export.cpp(mbedTLS sockets, HTTP/1.x, chunked decoding, a real async send) is gone: the merge takesmain's libSceHttp2 sources unchanged. The test against a live publisher host is gone too. The PR diff againstmainis 9 files, +125/-10. The same approach is open upstream as boykopovar#11145. If that merges and syncs, this change should give way to it.Tested
Tests need no external network. A loopback h2 server presents a leaf signed by the fixture CA, with the host-name check on. Each
guest_http2_host_roots_<list>run serves its ownCA_LIST.certhrough the working-directory override:trusted(list = fixture CA): a context with no certificate connects; a context with an unrelated CA connects (host roots come after its own); a context with the fixture CA connects.untrusted(list = unrelated CA),missing(path blocked),empty,blank(text, no certificate): the first two contexts fail verification; the context with the fixture CA still connects.0x8095f006.Mutation checks (each restored exactly afterwards):
Transport.cppcall:host_roots_trustedfails, the others pass.host_roots_trustedfails.guest_http2_transportandhost_roots_untrusted/missing/empty/blankfail.Results (fresh builds,
ctest --timeout 120 -R 'http|Http|ssl|Ssl|sandbox_certificate'):guest_http2_dns_first, which is Wine-only and has nothing to do with this change: its first check expectsgetaddrinfoto returnWSANOTINITIALISEDbeforeWSAStartup, and Wine's returns 0 (a standalone probe shows the same). Before the libkernel fix,guest_sandbox_certificatesand every host-trust request failed under Wine with "Opening the Windows trusted root store: File not found".tools/check_conventions.py --base origin/main: all checks passed. Public-header audit: 368 libraries, 12811 exports, unique declarations verified.Still open
sceHttp2SendRequestAsyncstill completes offline with0x80436063(fix(libSceHttp2): complete sceHttp2SendRequestAsync offline instead of throwing #41). Moving it onto the transport is a separate change.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)