Repository navigation
feat(libSceLibreSsl3): implement the RSA, DH and DSA get0 key and parameter accessors - #10490
alvaroelpob wants to merge 14 commits into
Conversation
Progress report (91db3f7 → 7c7b3f8)📈 System libraries: 27.12% (+0.02%, +5 implemented, +4 declared functions) ✅ 5 implemented
🆕 4 declared as stubs
Changed libraries (implemented exports)
|
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed head f05c46e39d10a6d3a5cfe5eb481313ea460b49c3.
I checked the five accessors against the pinned LibreSSL 4.0.0 structures and getter behavior. The asserted sizes/offsets for RSA, DH, and DSA match their field order, and each accessor writes only non-null output pointers from the specified fields. The null-key exception path and output-selection tests are consistent with the stated compatibility approach. I found no blocking correctness issue in this diff.
The PR reports focused accessor tests and a 2005/2006 full CTest run, with the remaining failure also present on main; I did not reproduce these runs locally. Current convention, labels, eligibility, and report checks pass; Linux, Windows, register-context, relinker, write-watch, and ASan jobs are skipped. The overlap report with #10557 lists shared build/export/debt files but no same exports; coordinate those file edits when composing the changes.
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Exports introduced here that are already present in
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
f05c46e to
476c2c6
Compare
|
Rebased on |
|
@alvaroelpob Thanks for moving the declarations; the header part is resolved. One behaviour question remains: the PR still rejects a null key unconditionally, and five tests require calls with all outputs null to throw. In pinned LibreSSL 4.0.0 these getters only dereference the key for the outputs that are requested, so a call with no outputs is a no-op. Please either follow that (no-output call returns without touching the key, with tests for it, and the body/debt updated), or cite a console-side source showing the different contract. The |
|
Windows run of
Not run: a title. AI-assisted: yes (Claude Code) |
…, DH and DSA get0 key and parameter accessors Took the PR's DH_get0_pqg/DH_get0_key/DSA_get0_pqg/DSA_get0_key (KeyComponents.cpp, its test and CMake entries); kept our RSA_get0_key (Keys.cpp, on libSceLibreSsl's 2.6.3 RSA that both modules share) instead of the PR's 4.0.0-layout one and dropped its RSA test case; dropped a duplicate MD5/SHA1 debt bullet. (cherry picked from commit 02f89af527abd671b8348af4393bb3d83099fdda)
476c2c6 to
dfb0b57
Compare
|
@oneandonlydean Followed LibreSSL 4.0.0: the five getters now read the key only for the outputs requested, so a call with every output null returns without touching it, and a null key throws only when an output is requested (cc8bfe4). The tests use |
ahmadmuj
left a comment
There was a problem hiding this comment.
Checked head dfb0b57aa4d2 (base 6e775f452ae9; also merges clean onto main ae7d59258ea7). Linux, GCC 13.3, Release.
What I ran:
guest_libressl3_key_componentson the merge: pass.public_headers: pass.check_conventions.py: pass.- Compiled the
rsa_st/dh_st/dsa_stfrom the 4.0.0*_local.hat ce488b78: 152/128/112 bytes, and every offset you read matches. The get0 bodies matchrsa_lib.c,dh_lib.canddsa_lib.c, and the new null-key handling is right. - Mutated the offsets and the null-key paths (9 mutations): all go red.
- Merged #10915 (head
5576345be456, the 2.5.4 RSA in libSceLibreSsl) on top and ran a probe through both libraries.
So on its own this is right for 4.0.0. The problem is where an l3 title gets its RSA from, same pattern I raised on #10960:
- In the 3.20 table, libSceLibreSsl3 also exports
RSA_new,d2i_RSA_PUBKEY,EVP_PKEY_get1_RSA,PEM_read_RSAPrivateKeyetc. under the same NIDs as libSceLibreSsl. It has noRSA_set0_key, andrsa_stis private in 4.0.0, so a title can't build its own RSA. Every key that reachesRSA_get0_keycomes from one of those shared calls. - Our libSceLibreSsl3 doesn't implement them, so on Linux they bind to libSceLibreSsl.
LD_DEBUG=bindingson an exe that only needslibSceLibreSsl3.prx:PFxpQ6lkQP0(d2i_RSA_PUBKEY) andkADEz2eAE7c(RSA_new) bind tolibSceLibreSsl.prx,9RMSBpPZVdk(RSA_get0_key) binds tolibSceLibreSsl3.prx. - l1 uses the public 2.5.4 layout, which still has
ENGINE *engineat 24, sonis at 32.
Composed run, 2048-bit key: l1 d2i_RSA_PUBKEY -> l3 RSA_get0_key(rsa, &n, &e, &d) gives n = NULL, e = the modulus (top=32, low word 0xd941211635074acf), d = 65537. Each field comes from one slot too early. Both PRs' own tests pass, so it only shows once both land.
DSA has the same shift, read from the headers, not run: 2.5.4 dsa_st has int write_params after version, so p is at 24, not 16. l3 DSA_get0_pqg would hand back write_params (1 after DSA_new) as p. Nothing creates an l1 DSA yet, so that one is latent. DH is fine: the offsets are the same in 2.5.4 and 4.0.0.
What I'd suggest: read RSA and DSA through the 2.5.4 layout (#10915's LibreSslRsa for RSA). Titles can't see the 4.0.0 offsets anyway, and that's the object they actually get. The other way is to implement the l3 NIDs for every call that creates or frees these keys, which is a lot more surface. The debt line "No export of this module creates a key yet, so only keys the caller builds reach them" should change either way: the keys come from libSceLibreSsl.
|
@alvaroelpob @oneandonlydean @ahmadmuj firmware 13.42 data on both open points. These are runs of the decrypted No-output calls. The module handles them the way this head does. I ran its
Where an l3
So on 13.42 the module's own RSA objects use these 4.0.0 offsets. Reading through the 2.5.4 layout would shift those objects by one slot. The l1-created keys in your composed run reach l3 through the emulator binding the missing l3 NIDs to libSceLibreSsl; on 13.42, libSceLibreSsl3 has those NIDs itself. |
|
@ahmadmuj @BunnyFl thanks, both. BunnyFl's 13.42 run shows that The mismatch in the composed run is real on our side, though. This library doesn't list those key-creating exports yet, so on Linux they bind to libSceLibreSsl and hand over 2.5.4 objects. e2d9aaa replaces the debt entry's "only keys the caller builds" with that gap. The fix is to implement them in libSceLibreSsl3, which is beyond these five accessors. |
|
A Windows rerun of the new head
AI-assisted: yes (Claude Code) |
e2d9aaa to
4d500b4
Compare
|
@oneandonlydean done in 2f913e3, 0814670 and ad00df5 (head ad00df5):
Full |
|
@alvaroelpob #13267 ( Since #13267 has no dependencies and this PR waits on #9535, #9536, #9571, #9970, #10452 and #10461, I propose #13267 lands first. I merged your head
With those, every libSceLibreSsl3 source, both of your tests and |
ad00df5 to
1685871
Compare
|
Rebased on @msbutt1 thanks for checking the merge. This PR was opened first, so I'm keeping the order: Depends on stays as is, and #13267 rebases after it. Both layouts are the same 152 bytes, so #13267 can name the fields after |
|
@alvaroelpob sounds good, #10490 goes first. #13267 now declares |
…ssors only for requested outputs
…tput key accessor calls
…RSA and PEM_read_RSAPrivateKey so they no longer bind to libSceLibreSsl
…d to libSceLibreSsl3
…the pending exports
1685871 to
7c7b3f8
Compare
|
#13267 merged first, so this is rebased on |
What
Implements
RSA_get0_key,DH_get0_pqg,DH_get0_key,DSA_get0_pqgandDSA_get0_keyin libSceLibreSsl3, which threw and were declared without parameters.The module is LibreSSL 4.0.0 (firmware 13.40 measurements in #8981). Signatures, layouts and results follow that release's
rsa_local.h,rsa_lib.c,dh_local.h,dh_lib.c,dsa_local.handdsa_lib.c. Each writes the requested fields through the non-null output pointers and leaves the others alone:void RSA_get0_key(const RSA*, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d)n(24),e(32),d(40)void DH_get0_pqg(const DH*, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g)p(8),q(64),g(16)void DH_get0_key(const DH*, const BIGNUM** pub_key, const BIGNUM** priv_key)pub_key(32),priv_key(40)void DSA_get0_pqg(const DSA*, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g)p(16),q(24),g(32)void DSA_get0_key(const DSA*, const BIGNUM** pub_key, const BIGNUM** priv_key)pub_key(40),priv_key(48)The structs are 152, 128 and 112 bytes. The offsets were checked with
static_asserts and againstoffsetoffrom the 4.0.0 headers compiled on x86-64; the 4.0.0RSAhas noenginefield, unlike the 2.5.4 one in libSceLibreSsl. LibreSSL reads the key only for the outputs requested: with every output null the call returns without reading it, and a null key throws only when an output is requested, where LibreSSL would dereference it. This library doesn't list the module's ownRSA_new,d2i_RSA_PUBKEYand the other key-creating exports yet, so on Linux a title's import of them binds to libSceLibreSsl, whoseRSAandDSAuse the 2.5.4 layout; the debt entry records it. On firmware 13.42 the module makes its own keys with these 4.0.0 offsets.The debt entry records the source and what is unverified. The pending-export count drops from 84 to 79, and the five names join the exclusion list.
Tested
Ubuntu 26.04 (WSL2, kernel 6.18), GCC 15.2.0, Release, full build with
BUILD_TESTING=ONonmain379b1dc. There is one commit per function, and each adds that function with its test block and debt update. Each was built and itsguest_libressl3_key_componentstest andcheck_conventions.pyrun on its own.guest_libressl3_key_componentstest, onLibreSsl3Rsa,LibreSsl3DhandLibreSsl3Dsaobjects whose every pointer field holds a distinct address. Each accessor returns exactly its slots, leaves outputs passed as null and untouched outputs alone, returns null for fields that are null, returns without reading a null key when every output is null, and throws for a null key when any output is requested.ctest -j16at the last commit: 2005/2006 pass.agc_driver_multisample_retirementfails the same way onmainon this machine.maine7e3e9c, head 476c2c6. The branch still merged cleanly, but after refactor(libs): add full export headers for libs #10706public_headersfails on the merge: the exports kept their(void)stubs ininclude/Api.hppand the test redeclared them. 476c2c6 (refactor(libSceLibreSsl3): declare the key component exports in the public header) puts the real signatures and their structs inlibSceLibreSsl3/include/Api.hppand drops the test's redeclarations. Full build andctest -j16: 2202/2203 pass;agc_driver_multisample_retirementfails the same way on thatmain.check_conventions.py --base upstream/mainpasses.main6e775f4, head dfb0b57, to resolve the conflicts withmainon the sharedCMakeLists.txtand debt-file lines; both sides are kept and the count is 84 minus this PR's exports. Review fixes cc8bfe4, 1a7514f and dfb0b57 make a call with every output null return without reading the key, build the tests on the public structs and update the debt entry;guest_libressl3_key_componentspasses. Full build andctest -j16: 2268/2269 pass;agc_driver_multisample_retirementfails the same way on thatmain.check_conventions.py --base upstream/mainpasses.ctest -j16onmain6e775f4: 2268/2269 pass;agc_driver_multisample_retirementfails the same way on thatmain.check_conventions.py --base upstream/mainpasses.main74acfad (after feat(libSceLibreSsl3): implement ASN.1 integer decoding #10948), head 4d500b4, to resolve the conflicts withmainon the sharedCMakeLists.txtand debt-file lines; both sides are kept and the count is 83 minus this PR's exports. Full build andctest -j16: 2431/2432 pass;agc_driver_multisample_retirementfails the same way on thatmain.check_conventions.py --base upstream/mainpasses.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)