Skip to content

fix(libSceHttp2): trust the host CA list for HTTPS requests - #33

Open
hypermoist wants to merge 5 commits into
mainfrom
feat/engine-https
Open

hypermoist wants to merge 5 commits into
mainfrom
feat/engine-https

Conversation

@hypermoist

@hypermoist hypermoist commented Oct 27, 2026 •

Copy link
Copy Markdown

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) gets 0x8095f00c (unknown CA) from sceSslConnect. The transport then throws sceHttp2: TLS failed. Before the sync, the fork's offline stub returned 0x80436063 for this request instead. That code now only comes from the offline sceHttp2SendRequestAsync completion added in #41, which never touches the network.

Change.

  • libSceSsl gets SslTrustHostRoots_nid_no_patch(connection), declared in Ssl.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.
  • The list is parsed once per process into its own allocation pool, not the title's sceSslInit pool. It is linked after the context's own authorities, so a title that loads its own CA keeps working.
  • A missing list, or one with no certificate, adds nothing. Behaviour is then the same as before: only the context's authorities are trusted and an unknown server fails verification.
  • Transport.cpp calls the helper right after sceSslCreateConnection. Verification stays on with the request's check flags. No host names, titles, stand-in servers or tokens.
  • libkernel: the Windows ROOT and Disallowed stores are now opened read-only without 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 with ERROR_FILE_NOT_FOUND, so no list could be built. Without the flag, the same profile lists 122 roots.
  • Test-only change: each 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 takes main's libSceHttp2 sources unchanged. The test against a live publisher host is gone too. The PR diff against main is 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 own CA_LIST.cer through 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.
  • An unknown connection id returns 0x8095f006.

Mutation checks (each restored exactly afterwards):

  • Removing the Transport.cpp call: host_roots_trusted fails, the others pass.
  • Not linking host roots after the context's authorities: host_roots_trusted fails.
  • Disabling the known-CA check in the transport: guest_http2_transport and host_roots_untrusted/missing/empty/blank fail.

Results (fresh builds, ctest --timeout 120 -R 'http|Http|ssl|Ssl|sandbox_certificate'):

  • Linux x86_64, GCC Release: 44/44 pass.
  • Windows (WinLibs GCC 15.2 cross build, run under Wine): 45/46 pass. The failure is guest_http2_dns_first, which is Wine-only and has nothing to do with this change: its first check expects getaddrinfo to return WSANOTINITIALISED before WSAStartup, and Wine's returns 0 (a standalone probe shows the same). Before the libkernel fix, guest_sandbox_certificates and 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

  • The T52 case itself, a game reaching its publisher's real service, has not been run with a game on this head.
  • HTTP/1.x requests (template version 1 or 2) still throw in the transport. I left them out because nothing here shows they are needed for this case.
  • sceHttp2SendRequestAsync still completes offline with 0x80436063 (fix(libSceHttp2): complete sceHttp2SendRequestAsync offline instead of throwing #41). Moving it onto the transport is a separate change.
  • Not measured: that the console trusts public roots by default, and its exact root set (recorded in the debt entries).

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: T52
  • GPUs tested: n/a
  • AI-assisted: yes

…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
hypermoist 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.
@hypermoist hypermoist changed the title feat(libSceHttp2): network transmission for sceHttp2SendRequest with host CA roots fix(libSceHttp2): trust the host CA list for HTTPS requests Oct 28, 2026
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