Merge pull request #10449 from alvaroelpob/feat/libscelibressl-rsa-flags-size

feat(libSceLibreSsl): implement RSA_flags and RSA_size
This commit is contained in:
Adrià authored and GitHub committed 2026-10-26 21:26:37 +01:00
commit c8809e82e4
6 files changed
+221 -14

No files matched your search

+12 -1
View File
@@ -1,4 +1,4 @@
add_library(libSceLibreSsl SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Digest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Runtime.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Aes.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Error.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Ocsp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Stack.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Ui.cpp)
add_library(libSceLibreSsl SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Digest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Runtime.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Aes.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Error.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Ocsp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Stack.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Ui.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rsa.cpp)
target_include_directories(libSceLibreSsl PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(libSceLibreSsl PRIVATE mbedcrypto)
configure_windows_unwind(libSceLibreSsl)
@@ -110,6 +110,17 @@ if(BUILD_TESTING)
set_tests_properties(guest_libressl_ui PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
endif()
add_test_executable(guest_libressl_rsa_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslRsa.cpp)
target_include_directories(guest_libressl_rsa_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_libressl_rsa_tests PRIVATE libSceLibreSsl)
configure_windows_unwind(guest_libressl_rsa_tests)
add_test(NAME guest_libressl_rsa COMMAND guest_libressl_rsa_tests)
set_tests_properties(guest_libressl_rsa PROPERTIES TIMEOUT 30)
if(WIN32)
set_tests_properties(guest_libressl_rsa PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
endif()
endif()
target_sources(libSceLibreSsl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/Cipher.cpp)
-10
View File
@@ -909,11 +909,6 @@ int APS5_VABI PKCS12_parse_nid_postfix(void) {
return 0;
}
int APS5_VABI RSA_flags_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI RSA_free_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
@@ -959,11 +954,6 @@ int APS5_VABI RSA_sign_nid_postfix(void) {
return 0;
}
int APS5_VABI RSA_size_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI RSA_verify_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
+35 -2
View File
@@ -81,6 +81,39 @@ struct LibreSslUiMethod {
UiPromptFunction constructPrompt;
};
struct LibreSslRsaMethod {
const char* name;
void* operations[8];
int flags;
char* appData;
void* sign;
void* verify;
void* keygen;
};
struct LibreSslRsa {
int pad;
std::int64_t version;
const LibreSslRsaMethod* meth;
void* engine;
void* n;
void* e;
void* d;
void* p;
void* q;
void* dmp1;
void* dmq1;
void* iqmp;
void* exData;
int references;
int flags;
void* methodModN;
void* methodModP;
void* methodModQ;
void* blinding;
void* mtBlinding;
};
extern "C" {
std::int64_t APS5_VABI ASN1_INTEGER_get_nid_postfix(const Asn1String* value);
@@ -270,7 +303,7 @@ int APS5_VABI PEM_write_bio_X509_nid_postfix(void);
int APS5_VABI PKCS12_PBE_add_nid_postfix(void);
int APS5_VABI PKCS12_free_nid_postfix(void);
int APS5_VABI PKCS12_parse_nid_postfix(void);
int APS5_VABI RSA_flags_nid_postfix(void);
int APS5_VABI RSA_flags_nid_postfix(const LibreSslRsa* rsa);
int APS5_VABI RSA_free_nid_postfix(void);
int APS5_VABI RSA_generate_key_ex_nid_postfix(void);
int APS5_VABI RSA_new_nid_postfix(void);
@@ -280,7 +313,7 @@ int APS5_VABI RSA_private_encrypt_nid_postfix(void);
int APS5_VABI RSA_public_decrypt_nid_postfix(void);
int APS5_VABI RSA_public_encrypt_nid_postfix(void);
int APS5_VABI RSA_sign_nid_postfix(void);
int APS5_VABI RSA_size_nid_postfix(void);
int APS5_VABI RSA_size_nid_postfix(const LibreSslRsa* rsa);
int APS5_VABI RSA_verify_nid_postfix(void);
int APS5_VABI RSA_verify_PKCS1_PSS_nid_postfix(void);
int APS5_VABI SSL_CIPHER_get_bits_nid_postfix(const void* cipher, std::int32_t* algorithmBits);
+54
View File
@@ -0,0 +1,54 @@
#include "prx/libSceLibreSsl/include/Api.hpp"
#include <bit>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>
#include "prx/libc/include/General.hpp"
struct LibreSslBignum {
std::uint64_t* d;
int top;
int dmax;
int neg;
int flags;
};
static_assert(sizeof(LibreSslBignum) == 24);
static_assert(offsetof(LibreSslBignum, top) == 8);
static_assert(sizeof(LibreSslRsaMethod) == 112);
static_assert(offsetof(LibreSslRsaMethod, flags) == 72);
static_assert(sizeof(LibreSslRsa) == 152);
static_assert(offsetof(LibreSslRsa, meth) == 16);
static_assert(offsetof(LibreSslRsa, n) == 32);
static_assert(offsetof(LibreSslRsa, flags) == 108);
namespace {
int ByteCount(const LibreSslBignum* number, const char* function) {
if (!number) throw std::invalid_argument(std::string(function) + ": null modulus");
if (number->top == 0) return 0;
if (number->top < 0) throw std::invalid_argument(std::string(function) + ": negative modulus word count");
if (!number->d) throw std::invalid_argument(std::string(function) + ": null modulus words");
const std::int64_t bits = static_cast<std::int64_t>(number->top - 1) * 64 + std::bit_width(number->d[number->top - 1]);
if (bits > INT_MAX - 7) throw std::invalid_argument(std::string(function) + ": modulus bit count overflows int");
return static_cast<int>((bits + 7) / 8);
}
}
extern "C" {
int APS5_VABI RSA_flags_nid_postfix(const LibreSslRsa* rsa) {
if (!rsa) return 0;
if (!rsa->meth) throw std::invalid_argument(std::string(__func__) + ": null method");
return rsa->meth->flags;
}
int APS5_VABI RSA_size_nid_postfix(const LibreSslRsa* rsa) {
if (!rsa) throw std::invalid_argument(std::string(__func__) + ": null key");
return ByteCount(static_cast<const LibreSslBignum*>(rsa->n), __func__);
}
}
+118
View File
@@ -0,0 +1,118 @@
#include "prx/libSceLibreSsl/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <source_location>
#include <stdexcept>
struct TestBignum {
std::uint64_t* d;
int top;
int dmax;
int neg;
int flags;
};
struct TestRsaMethod {
const char* name;
void* operations[8];
int flags;
char* appData;
void* sign;
void* verify;
void* keygen;
};
struct TestRsa {
int pad;
std::int64_t version;
const TestRsaMethod* meth;
void* engine;
void* n;
void* rest[15];
};
static_assert(offsetof(TestRsaMethod, flags) == 72);
static_assert(offsetof(TestRsa, meth) == 16 && offsetof(TestRsa, n) == 32 && sizeof(TestRsa) == 160);
static const LibreSslRsa* Rsa(const TestRsa* rsa) {
return reinterpret_cast<const LibreSslRsa*>(rsa);
}
static void Require(bool condition, std::source_location location = std::source_location::current()) {
if (condition) return;
std::fprintf(stderr, "LibreSSL RSA check failed at line %u\n", location.line());
std::abort();
}
template<typename TAction> static void RequireThrows(TAction action, std::source_location location = std::source_location::current()) {
try { action(); } catch (const std::exception&) { return; }
Require(false, location);
}
static void TestFlags() {
TestRsaMethod method {};
TestRsa rsa {};
rsa.meth = &method;
Require(RSA_flags_nid_postfix(nullptr) == 0);
Require(RSA_flags_nid_postfix(Rsa(&rsa)) == 0);
method.flags = 0x0400;
Require(RSA_flags_nid_postfix(Rsa(&rsa)) == 0x0400);
method.flags = -1;
Require(RSA_flags_nid_postfix(Rsa(&rsa)) == -1);
rsa.meth = nullptr;
RequireThrows([&] { RSA_flags_nid_postfix(Rsa(&rsa)); });
}
static int Size(TestBignum* modulus) {
TestRsa rsa {};
rsa.n = modulus;
return RSA_size_nid_postfix(Rsa(&rsa));
}
static void TestSize() {
std::uint64_t words[32] {};
TestBignum modulus {words, 0, 32, 0, 0};
Require(Size(&modulus) == 0);
modulus.d = nullptr;
Require(Size(&modulus) == 0);
modulus.d = words;
modulus.top = 1;
words[0] = 1;
Require(Size(&modulus) == 1);
words[0] = 0xFF;
Require(Size(&modulus) == 1);
words[0] = 0x100;
Require(Size(&modulus) == 2);
words[0] = 0x8000000000000000ull;
Require(Size(&modulus) == 8);
modulus.top = 2;
words[1] = 1;
Require(Size(&modulus) == 9);
modulus.top = 32;
words[31] = 0xC000000000000000ull;
Require(Size(&modulus) == 256);
modulus.neg = 1;
Require(Size(&modulus) == 256);
modulus.neg = 0;
modulus.top = 16;
words[15] = 0x00FFFFFFFFFFFFFFull;
Require(Size(&modulus) == 127);
words[15] = 0;
Require(Size(&modulus) == 120);
modulus.top = -1;
RequireThrows([&] { Size(&modulus); });
modulus.top = 1;
modulus.d = nullptr;
RequireThrows([&] { Size(&modulus); });
RequireThrows([] { Size(nullptr); });
RequireThrows([] { RSA_size_nid_postfix(nullptr); });
}
int main() {
TestFlags();
TestSize();
std::puts("libSceLibreSsl RSA tests passed");
}
+2 -1
View File
@@ -2,7 +2,7 @@
### Unknown function info
- [libSceLibreSsl pending exports](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - 321 named callable exports are listed in the [PS5 3.20 export table](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceLibreSsl.c) and were cross-checked against the same module in PS5 firmware 13.60. Their signatures and behaviour are unverified; the declarations use the no-parameter unknown-signature convention and throw through `NotImplemented_nid_no_patch`.
- [libSceLibreSsl pending exports](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - 319 named callable exports are listed in the [PS5 3.20 export table](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceLibreSsl.c) and were cross-checked against the same module in PS5 firmware 13.60. Their signatures and behaviour are unverified; the declarations use the no-parameter unknown-signature convention and throw through `NotImplemented_nid_no_patch`.
- [MD4, MD5, SHA1, SHA224, SHA256, SHA384 and SHA512 Init/Update/Final and SHA256](../../../core/libs/prx/libSceLibreSsl/src/Digest.cpp) (libSceLibreSsl) - signatures and context layouts follow the [LibreSSL headers](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/sha/sha.h), and buffering and `Final` follow its [sources](https://github.com/libressl/openbsd/tree/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/sha); nothing is checked on the console. Null contexts, null input with a nonzero length, null digest buffers in the 32-bit `Final` functions and a buffered byte count that is not below the block size, which LibreSSL does not check, throw
- [DES_set_key, DES_ecb_encrypt, DES_set_odd_parity](../../../core/libs/prx/libSceLibreSsl/Export.cpp) (libSceLibreSsl) - the 128-byte `DES_key_schedule` holds the 8-byte key followed by zeros instead of LibreSSL's precomputed subkeys, so a title reading its contents sees different bytes; `DES_ecb_encrypt` derives the subkeys through mbedtls on each call. Not compared with the console. Results follow LibreSSL [des_key.c](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/des/des_key.c) and [des.c](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/des/des.c): `DES_set_key` skips the parity and weak-key checks and returns 0, as it does while `DES_check_key` is 0 (that variable is not in the PS5 export inventory), a nonzero `enc` encrypts, and `DES_set_odd_parity` sets each byte's low bit for odd parity. Null pointers throw where LibreSSL faults
- [X509_verify_cert_error_string](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - no console call is verified. The 64-bit argument, low-32-bit lookup, messages and shared numeric fallback follow [LibreSSL 2.5.4](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto/x509/x509_txt.c), the version identified in [published firmware 13.40 measurements](https://github.com/boykopovar/AnyPS5/discussions/8981#discussioncomment-19111214). Console modifications and other firmware versions remain unverified. Unknown-code results share an overwritten static buffer and are not safe for concurrent use, as in that release; code 1 and codes above 54 use the numeric fallback.
@@ -14,6 +14,7 @@
- [SSL_CIPHER_get_bits, SSL_CIPHER_get_name and SSL_CIPHER_get_version](../../../core/libs/prx/libSceLibreSsl/src/Cipher.cpp) - the 88-byte guest cipher layout and these calls are not console-verified. They follow [LibreSSL 2.5.4 ssl.h](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libssl/ssl.h) and [ssl_ciph.c](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libssl/ssl_ciph.c), matching the version in [published firmware 13.40 measurements](https://github.com/boykopovar/AnyPS5/discussions/8981#discussioncomment-19111214). Console modifications and other firmware layouts remain unverified. Protocol labels use the full 64-bit cipher ID, not the protocol flags; TLS 1.2 ciphers still report `TLSv1/SSLv3`, as in that release.
- [sk_num, sk_value, sk_pop, sk_pop_free](../../../core/libs/prx/libSceLibreSsl/src/Stack.cpp) (libSceLibreSsl) - the 32-byte `_STACK` layout (`num`, `data`, `sorted`, `num_alloc`, `comp`) and the results follow [LibreSSL 2.5.4](https://github.com/libressl/openbsd/tree/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto/stack) `stack.h` and `stack.c`, the version identified in [published firmware 13.40 measurements](https://github.com/boykopovar/AnyPS5/discussions/8981#discussioncomment-19111214); nothing is checked on the console. `sk_pop_free` releases the element array and the stack with the guest `free`, as the module would through libc. No export of this module creates a stack yet, so only stacks the caller builds reach them. A null element array that LibreSSL would read through, and a null free function with a non-null element, throw where LibreSSL faults
- [RSA_flags, RSA_size](../../../core/libs/prx/libSceLibreSsl/src/Rsa.cpp) (libSceLibreSsl) - nothing is checked on the console. Layouts and results follow [LibreSSL 2.5.4](https://github.com/libressl/openbsd/tree/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto) `rsa.h`, `rsa_crpt.c` and `bn_lib.c`, the version in the [firmware 13.40 measurements](https://github.com/boykopovar/AnyPS5/discussions/8981#discussioncomment-19111214). No export of this module creates a key yet, so only keys the caller builds reach them. `RSA_size` counts the modulus bytes from its top word, as `BN_num_bytes`, so a zero top word is not skipped. A null method, a null key or modulus, and a positive word count with null words, which LibreSSL dereferences, throw, as do a negative word count and a bit count that overflows `int`
### Functional