diff --git a/core/libs/prx/libSceLibreSsl/CMakeLists.txt b/core/libs/prx/libSceLibreSsl/CMakeLists.txt index 3621baad39..7f27debea6 100644 --- a/core/libs/prx/libSceLibreSsl/CMakeLists.txt +++ b/core/libs/prx/libSceLibreSsl/CMakeLists.txt @@ -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 ${CMAKE_CURRENT_SOURCE_DIR}/src/Rsa.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 ${CMAKE_CURRENT_SOURCE_DIR}/src/Pkey.cpp) target_include_directories(libSceLibreSsl PRIVATE ${LIBS_INCLUDE_DIR}) target_link_libraries(libSceLibreSsl PRIVATE mbedcrypto) configure_windows_unwind(libSceLibreSsl) @@ -121,6 +121,17 @@ if(BUILD_TESTING) set_tests_properties(guest_libressl_rsa PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + + add_test_executable(guest_libressl_pkey_type_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslPkeyType.cpp) + target_include_directories(guest_libressl_pkey_type_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_libressl_pkey_type_tests PRIVATE libSceLibreSsl libc) + configure_windows_unwind(guest_libressl_pkey_type_tests) + add_test(NAME guest_libressl_pkey_type COMMAND guest_libressl_pkey_type_tests) + set_tests_properties(guest_libressl_pkey_type PROPERTIES TIMEOUT 30) + if(WIN32) + set_tests_properties(guest_libressl_pkey_type PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() endif() target_sources(libSceLibreSsl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/Cipher.cpp) diff --git a/core/libs/prx/libSceLibreSsl/Export.cpp b/core/libs/prx/libSceLibreSsl/Export.cpp index 00ace935b0..70b83b065a 100644 --- a/core/libs/prx/libSceLibreSsl/Export.cpp +++ b/core/libs/prx/libSceLibreSsl/Export.cpp @@ -639,11 +639,6 @@ int APS5_VABI EVP_PKEY_set1_RSA_nid_postfix(void) { return 0; } -int APS5_VABI EVP_PKEY_type_nid_postfix(void) { - NotImplemented_nid_no_patch(__func__); - return 0; -} - int APS5_VABI EVP_aes_128_cbc_nid_postfix(void) { NotImplemented_nid_no_patch(__func__); return 0; diff --git a/core/libs/prx/libSceLibreSsl/include/Api.hpp b/core/libs/prx/libSceLibreSsl/include/Api.hpp index a114265d0c..46f54dc043 100644 --- a/core/libs/prx/libSceLibreSsl/include/Api.hpp +++ b/core/libs/prx/libSceLibreSsl/include/Api.hpp @@ -246,7 +246,7 @@ int APS5_VABI EVP_PKEY_get1_RSA_nid_postfix(void); int APS5_VABI EVP_PKEY_id_nid_postfix(void); int APS5_VABI EVP_PKEY_new_nid_postfix(void); int APS5_VABI EVP_PKEY_set1_RSA_nid_postfix(void); -int APS5_VABI EVP_PKEY_type_nid_postfix(void); +int APS5_VABI EVP_PKEY_type_nid_postfix(int type); int APS5_VABI EVP_aes_128_cbc_nid_postfix(void); int APS5_VABI EVP_aes_128_cfb8_nid_postfix(void); int APS5_VABI EVP_aes_128_ctr_nid_postfix(void); diff --git a/core/libs/prx/libSceLibreSsl/src/Pkey.cpp b/core/libs/prx/libSceLibreSsl/src/Pkey.cpp new file mode 100644 index 0000000000..244f5e5d36 --- /dev/null +++ b/core/libs/prx/libSceLibreSsl/src/Pkey.cpp @@ -0,0 +1,44 @@ +#include "prx/libSceLibreSsl/include/Api.hpp" +#include "prx/libc/include/General.hpp" + +namespace { + +constexpr int NidUndef = 0; +constexpr int NidRsaEncryption = 6; +constexpr int NidRsa = 19; +constexpr int NidDhKeyAgreement = 28; +constexpr int NidDsaWithSha = 66; +constexpr int NidDsa2 = 67; +constexpr int NidDsaWithSha1Old = 70; +constexpr int NidDsaWithSha1 = 113; +constexpr int NidDsa = 116; +constexpr int NidEcPublicKey = 408; +constexpr int NidHmac = 855; +constexpr int NidCmac = 894; + +} + +extern "C" { + +int APS5_VABI EVP_PKEY_type_nid_postfix(int type) { + switch (type) { + case NidRsaEncryption: + case NidRsa: + return NidRsaEncryption; + case NidDhKeyAgreement: + case NidEcPublicKey: + case NidHmac: + case NidCmac: + return type; + case NidDsaWithSha: + case NidDsa2: + case NidDsaWithSha1Old: + case NidDsaWithSha1: + case NidDsa: + return NidDsa; + default: + return NidUndef; + } +} + +} diff --git a/core/libs/tests/GuestLibreSslPkeyType.cpp b/core/libs/tests/GuestLibreSslPkeyType.cpp new file mode 100644 index 0000000000..a8ba0075e1 --- /dev/null +++ b/core/libs/tests/GuestLibreSslPkeyType.cpp @@ -0,0 +1,25 @@ +#include "prx/libSceLibreSsl/include/Api.hpp" +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include +#include +#include + +static void Require(bool condition, std::source_location location = std::source_location::current()) { + if (condition) return; + std::fprintf(stderr, "LibreSSL EVP_PKEY_type check failed at line %u\n", location.line()); + std::abort(); +} + +int main() { + Require(EVP_PKEY_type_nid_postfix(6) == 6); + Require(EVP_PKEY_type_nid_postfix(19) == 6); + Require(EVP_PKEY_type_nid_postfix(408) == 408); + Require(EVP_PKEY_type_nid_postfix(855) == 855); + Require(EVP_PKEY_type_nid_postfix(894) == 894); + Require(EVP_PKEY_type_nid_postfix(28) == 28); + for (const int type : {66, 67, 70, 113, 116}) Require(EVP_PKEY_type_nid_postfix(type) == 116); + for (const int type : {0, -1, 1, 5, 7, 64, 65, 117, 407, 409, 672, 854, 856, 811, 815, 893, 895, 946, 947, 948, INT_MIN, INT_MAX}) Require(EVP_PKEY_type_nid_postfix(type) == 0); + std::puts("libSceLibreSsl EVP_PKEY_type tests passed"); +} diff --git a/docs/dev/debt/libSceLibreSsl.md b/docs/dev/debt/libSceLibreSsl.md index 8e10d3844d..7ff7855a6b 100644 --- a/docs/dev/debt/libSceLibreSsl.md +++ b/docs/dev/debt/libSceLibreSsl.md @@ -2,7 +2,7 @@ ### Unknown function info -- [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`. +- [libSceLibreSsl pending exports](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - 318 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. @@ -15,6 +15,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` +- [EVP_PKEY_type](../../../core/libs/prx/libSceLibreSsl/src/Pkey.cpp) (libSceLibreSsl) - follows the method table of [LibreSSL 2.5.4](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto/asn1/ameth_lib.c#L83-L111) `ameth_lib.c` built without GOST and with no engine (every `ENGINE_` export throws): RSA (6) and its alias 19 give 6, the DSA types 66, 67, 70, 113 and 116 give 116, DH (28), EC (408), HMAC (855) and CMAC (894) give themselves, and every other type, the GOST types 811, 815, 946 and 947 included, gives 0. These results match [firmware 13.42's module run natively on a PC](https://github.com/boykopovar/AnyPS5/pull/10398#issuecomment-6406072913) for every type from -1000 to 5000 and the `int` extremes; nothing is checked on the console ### Functional