Repository navigation
Conversation
… ALPN to the handshake sceSslConnect verifies the server's chain under MBEDTLS_SSL_VERIFY_OPTIONAL and returns the first failure the connection's verify options select, with the SSL_ERROR_* codes KytyPS5 lists, instead of requiring a loaded CA and throwing. The result is final for the connection: close_notify is sent, later sceSslConnect calls return the same code, and sceSslRead and sceSslWrite throw. The ALPN list set with sceSslSetAlpn is split on commas and offered in the handshake, and sceSslGetAlpnSelected returns the protocol the server chose. The minimum version floors the handshake at TLS 1.2, the only version this build speaks. A socket that would block returns SSL_ERROR_WANT_POLLIN or WANT_POLLOUT from connect, read and write and the next sceSslConnect resumes the handshake; a reset, an end of stream without close_notify, a timeout and a fatal alert return their codes too.
loyalburrito
left a comment
There was a problem hiding this comment.
Thanks @frankea, this is careful work, and most of it I'd like to take. I checked it against the sources and on Linux (the PR says Linux wasn't tested): cherry-picked onto the branch's current head 2edaf44a6, the code applies cleanly (only the debt text conflicts). The rewritten transport tests and guest_ssl, guest_ssl_load and the pool-stats test pass 3 runs in a row. ASan+UBSan is clean, and TSan shows nothing in 10 transport runs. All ten codes match KytyPS5's src/libs/errno.h at the pinned 4865dd9.
One blocker and three smaller points before merging:
1. Blocking: the initial verify options make verification fail open. main records the initial options as "unknown, taken as 0". That was harmless while nothing read them. Now that sceSslConnect reads them, 0 means no verification: any title that never calls sceSslEnableVerifyOption accepts any certificate from any server, and the "no CA" throw that used to stop this is gone. That includes ffmpeg.prx, the importer this entry is about. Today the branch fails closed, so this turns an unknown into a man-in-the-middle exposure. CONTRIBUTING's rule for unknowns points the other way, and the one source we have does too: KytyPS5's HTTPS layer at the same commit starts with ssl_flags = 0xA7 (network.cpp:191: SERVER_VERIFY | CLIENT_VERIFY | CN_CHECK | KNOWN_CA_CHECK | SNI). That's libSceHttp's default, not libSceSsl's, but it's evidence for verify-on, not 0. Could the initial options be all five checks (0x3D: SERVER_VERIFY, CN_CHECK, NOT_AFTER, NOT_BEFORE, KNOWN_CA), recorded in the debt entry as unverified on a console? A title that explicitly disables a check still gets exactly what your code gives it. With no CA loaded, a default connection would then return SSL_ERROR_UNKNOWN_CA instead of throwing, which is better than today.
2. Two of the described mappings can't happen with this transport.
- "A reset returns
SSL_ERROR_SOCKET_CLOSED":Session::Receive/Sendturn every host error other than EAGAIN/EINTR intoMBEDTLS_ERR_NET_RECV_FAILED/SEND_FAILED, soMBEDTLS_ERR_NET_CONN_RESETis never produced and a reset still throws. - "A timeout returns
SSL_ERROR_READ_TIMEOUT":MBEDTLS_ERR_SSL_TIMEOUTonly comes from arecv_timeoutcallback, and none is set. An expired libSceNetSO_RCVTIMEOreaches us as EAGAIN, so a blocking socket's timeout returnsSSL_ERROR_WANT_POLLIN.
Either map ECONNRESET/EPIPE (and the Winsock equivalents) to MBEDTLS_ERR_NET_CONN_RESET in the BIO and tell a blocking socket's timeout apart from a non-blocking would-block, or drop those two cases and keep them as throws in the debt entry.
3. Record which code-for-which-situation choices are inferred. KytyPS5 gives names and values, not when the console returns them. The debt entry should say that the situation→code mapping is unverified, in particular:
WANT_POLLIN/WANT_POLLOUTversusSSL_ERROR_EAGAIN(0x8095F00F), which is also in the table;SOCKET_CLOSEDversusSSL_ERROR_EOF(0x8095177C) for a handshake cut short;INVALID_CERTas the catch-all;- a repeated
sceSslConnectreturning 0 instead of an error.
4. Rebase onto 2edaf44a6. A maintainer merged main into the branch, including boykopovar#5969, so the debt entry conflicts.
With 1 changed and 2–3 settled, I'll merge it into the PR branch with your authorship.
Generated by Claude Code
|
Update: boykopovar#6828 has been merged upstream (d704b80), so this branch is closed to new work and merging here would not reach upstream. Please open this against Generated by Claude Code |
|
Thanks for the review and the Linux and sanitizer runs; all four points are taken. Since boykopovar#6828 is in, this moves to a pull request against AI-assisted: yes (Claude Code). |
What
For boykopovar#6828 (upstream boykopovar#6828), the gap blawesom's rebase note named:
main'sverifyOptions,minimumVersionandalpn(boykopovar#5911) are recorded on the connection butSession::Configurenever reads them. This wires them in and replaces three throws with the console's result codes, so a title that configures its connection the way GT7 does (sceSslEnableVerifyOption,sceSslSetMinSslVersion,sceSslSetAlpn,sceSslGetAlpnSelected, all imported by PPSA01317) gets answers instead of aborts.MBEDTLS_SSL_VERIFY_OPTIONAL; afterwardssceSslConnectreturns the first failure the connection's verify options select, using SharpProspero'sSceSslVerifyOptionbits (SERVER_VERIFY0x1,CN_CHECK0x4,NOT_AFTER_CHECK0x8,NOT_BEFORE_CHECK0x10,KNOWN_CA_CHECK0x20) and the codes KytyPS5's errno list gives:SSL_ERROR_UNKNOWN_CA0x8095F00C,CN_CHECK0x8095F00B,NOT_AFTER_CHECK0x8095F00D,NOT_BEFORE_CHECK0x8095F00E,INVALID_CERT0x8095F00A for any other X.509 fault. The "no CA loaded" throw goes: with the CA check on it isSSL_ERROR_UNKNOWN_CA, which is what a console with no matching root would say. A failed verification is final: close_notify is sent, a repeatedsceSslConnectreturns the same code,sceSslRead/sceSslWritethrow. A repeatedsceSslConnectafter success returns 0 again rather than throwing.sceSslSetAlpn's string is split on commas and offered;sceSslGetAlpnSelectedreturns the server's choice, null before the handshake or when nothing was selected.SceSslVersionfloors the handshake at TLS 1.2, which is all this build speaks (1.3 is compiled out here), so the field is consumed without changing behaviour; the debt note says so.MBEDTLS_ERR_SSL_WANT_READ/WANT_WRITEreturnSSL_ERROR_WANT_POLLIN/WANT_POLLOUT(0x8095F013/14) from connect, read and write, and the nextsceSslConnectresumes the handshake instead of throwing "already connected"; a reset or an unannounced end of stream returnsSSL_ERROR_SOCKET_CLOSED(0x8095170D), a timeoutSSL_ERROR_READ_TIMEOUT(0x80951710), a fatal alertSSL_ERROR_FATAL_ALERT(0x8095F010). A write that blocks after sending part of the buffer returns the part sent. Everything else still throws throughFailas before.sceSslClose, and the initial verify options, which stay at 0 asmaindocuments, so a title that never enablesSERVER_VERIFYstill gets an unverified session; a fail-closed default is a maintainer decision that waits on a root bundle (feat(libkernel): serve the sandbox CA bundle from host TLS roots boykopovar/AnyPS5#5280). Both are called out in the debt note.Tested
Windows 11 26200, WinLibs MinGW-w64 GCC 15.2.0 posix-seh ucrt r7, Release,
BUILD_TESTING=ON, on 91d8416 + this commit:guest_ssl_transport_kernelandguest_ssl_transport_netrewritten around the new behaviour and passing, 5 runs each: no CA with the initial options connects (unverified, documented); no CA withSERVER_VERIFY | KNOWN_CA_CHECKreturnsSSL_ERROR_UNKNOWN_CAtwice and read throws; a certificate for another host returnsSSL_ERROR_CN_CHECKwith the checks on and 0 withCN_CHECKdisabled;SetMinSslVersion(TLS 1.2)+SetAlpn("h2,http/1.1")handshakes andGetAlpnSelectedreturnshttp/1.1, null before the handshake and null on a connection without an ALPN list; a secondsceSslConnectafter success returns 0; the existing cases (verify callback throws, closed descriptor throws, unknown flags, peek, pool accounting, socket left open, four parallel connections) unchanged.guest_ssl,guest_ssl_load,guest_memory_pool_statspass.python3 tools/check_conventions.py --base 91d8416fdpasses.Send/Receiveare untouched), a non-blocking socket end to end (the WANT_* mapping is covered by code reading only; the test sockets are blocking), and a title.Checklist
main; no other open PR implements the same functions (this targets feat(ssl): run TLS 1.2 client connections over Mbed TLS boykopovar/AnyPS5#6828's branch; feat(libSceSsl): run the TLS handshake and I/O over the title's socket with Mbed TLS boykopovar/AnyPS5#7319 carries the same wiring on a different transport and is a draft that depends on feat(ssl): run TLS 1.2 client connections over Mbed TLS boykopovar/AnyPS5#6828)NotImplemented_nid_no_patch); silent stubs are listed in the technical debt file.mdfiles or images added to the repository