feat(libSceLibreSsl): implement SSL_CTX_ctrl, SSL_CTX_callback_ctrl, SSL_CTX_set_msg_callback, SSL_CTX_set_verify and SSL_CTX_set_session_id_context

This commit is contained in:
Ahmad Mujahid committed 2026-10-25 23:21:47 +04:00
1 parent 4e083de859
commit 00846cdbfa
6 files changed
+747 -34

No files matched your search

@@ -99,6 +99,17 @@ if(BUILD_TESTING)
set_tests_properties(guest_libressl_ssl_ctx PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
endif()
add_test_executable(guest_libressl_ssl_ctx_fields_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslSslCtxFields.cpp)
target_include_directories(guest_libressl_ssl_ctx_fields_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_libressl_ssl_ctx_fields_tests PRIVATE libSceLibreSsl libc)
configure_windows_unwind(guest_libressl_ssl_ctx_fields_tests)
add_test(NAME guest_libressl_ssl_ctx_fields COMMAND guest_libressl_ssl_ctx_fields_tests)
set_tests_properties(guest_libressl_ssl_ctx_fields PROPERTIES TIMEOUT 30)
if(WIN32)
set_tests_properties(guest_libressl_ssl_ctx_fields PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
endif()
endif()
target_sources(libSceLibreSsl PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/Cipher.cpp)
-25
View File
@@ -973,21 +973,11 @@ int APS5_VABI SSL_CTX_add_client_CA_nid_postfix(void) {
return 0;
}
int APS5_VABI SSL_CTX_callback_ctrl_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_check_private_key_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_ctrl_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_free_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
@@ -1068,26 +1058,11 @@ int APS5_VABI SSL_CTX_set_info_callback_nid_postfix(void) {
return 0;
}
int APS5_VABI SSL_CTX_set_msg_callback_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_set_next_proto_select_cb_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_set_session_id_context_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_set_verify_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI SSL_CTX_use_PrivateKey_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
+67 -7
View File
@@ -52,9 +52,69 @@ struct Sha512Context {
};
struct LibreSslCtxInternal {
unsigned char beforeQuietShutdown[292];
std::uint16_t minVersion;
std::uint16_t maxVersion;
std::uint64_t options;
std::uint64_t mode;
void* newSessionCb;
void* removeSessionCb;
void* getSessionCb;
void* appVerifyCallback;
void* appVerifyArg;
void* clientCertCb;
void* appGenCookieCb;
void* appVerifyCookieCb;
void* infoCallback;
void* msgCallback;
void* msgCallbackArg;
void* defaultVerifyCallback;
void* generateSessionId;
void* tlsextServernameCallback;
void* tlsextServernameArg;
void* tlsextTicketKeyCb;
void* tlsextStatusCb;
void* tlsextStatusArg;
void* sessions;
std::uint64_t sessionCacheSize;
void* sessionCacheHead;
void* sessionCacheTail;
int sessionCacheMode;
int sessConnect;
int sessConnectRenegotiate;
int sessConnectGood;
int sessAccept;
int sessAcceptRenegotiate;
int sessAcceptGood;
int sessMiss;
int sessTimeout;
int sessCacheFull;
int sessHit;
int sessCbHit;
void* exData;
void* cipherListById;
void* cert;
void* clientCa;
std::int64_t maxCertList;
int readAhead;
int quietShutdown;
unsigned char rest[168];
unsigned int maxSendFragment;
void* clientCertEngine;
unsigned char tlsextTickKeyName[16];
unsigned char tlsextTickHmacKey[16];
unsigned char tlsextTickAesKey[16];
void* srtpProfiles;
void* nextProtosAdvertisedCb;
void* nextProtosAdvertisedCbArg;
void* nextProtoSelectCb;
void* nextProtoSelectCbArg;
void* alpnSelectCb;
void* alpnSelectCbArg;
unsigned char* alpnClientProtoList;
unsigned int alpnClientProtoListLen;
std::uint64_t tlsextEcpointformatlistLength;
std::uint8_t* tlsextEcpointformatlist;
std::uint64_t tlsextSupportedgroupsLength;
std::uint16_t* tlsextSupportedgroups;
};
struct LibreSslCtx {
@@ -279,9 +339,9 @@ int APS5_VABI SSL_CIPHER_get_bits_nid_postfix(const void* cipher, std::int32_t*
const char* APS5_VABI SSL_CIPHER_get_name_nid_postfix(const void* cipher);
char* APS5_VABI SSL_CIPHER_get_version_nid_postfix(const void* cipher);
int APS5_VABI SSL_CTX_add_client_CA_nid_postfix(void);
int APS5_VABI SSL_CTX_callback_ctrl_nid_postfix(void);
std::int64_t APS5_VABI SSL_CTX_callback_ctrl_nid_postfix(LibreSslCtx* ctx, int cmd, void* callback);
int APS5_VABI SSL_CTX_check_private_key_nid_postfix(void);
int APS5_VABI SSL_CTX_ctrl_nid_postfix(void);
std::int64_t APS5_VABI SSL_CTX_ctrl_nid_postfix(LibreSslCtx* ctx, int cmd, std::int64_t larg, void* parg);
int APS5_VABI SSL_CTX_free_nid_postfix(void);
void* APS5_VABI SSL_CTX_get_cert_store_nid_postfix(LibreSslCtx* ctx);
int APS5_VABI SSL_CTX_get_ex_data_nid_postfix(void);
@@ -302,11 +362,11 @@ void APS5_VABI SSL_CTX_set_default_passwd_cb_nid_postfix(LibreSslCtx* ctx, void*
void APS5_VABI SSL_CTX_set_default_passwd_cb_userdata_nid_postfix(LibreSslCtx* ctx, void* userdata);
int APS5_VABI SSL_CTX_set_ex_data_nid_postfix(void);
int APS5_VABI SSL_CTX_set_info_callback_nid_postfix(void);
int APS5_VABI SSL_CTX_set_msg_callback_nid_postfix(void);
void APS5_VABI SSL_CTX_set_msg_callback_nid_postfix(LibreSslCtx* ctx, void* callback);
int APS5_VABI SSL_CTX_set_next_proto_select_cb_nid_postfix(void);
void APS5_VABI SSL_CTX_set_quiet_shutdown_nid_postfix(LibreSslCtx* ctx, int mode);
int APS5_VABI SSL_CTX_set_session_id_context_nid_postfix(void);
int APS5_VABI SSL_CTX_set_verify_nid_postfix(void);
int APS5_VABI SSL_CTX_set_session_id_context_nid_postfix(LibreSslCtx* ctx, const unsigned char* sidCtx, unsigned int length);
void APS5_VABI SSL_CTX_set_verify_nid_postfix(LibreSslCtx* ctx, int mode, void* callback);
int APS5_VABI SSL_CTX_use_PrivateKey_nid_postfix(void);
int APS5_VABI SSL_CTX_use_PrivateKey_ASN1_nid_postfix(void);
int APS5_VABI SSL_CTX_use_PrivateKey_file_nid_postfix(void);
+224
View File
@@ -1,8 +1,12 @@
#include "prx/libSceLibreSsl/include/Api.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <string>
#include <utility>
#include "prx/libSceLibreSsl/include/Error.hpp"
#include "prx/libc/include/General.hpp"
static_assert(sizeof(LibreSslCtxInternal) == 464);
@@ -13,14 +17,120 @@ static_assert(offsetof(LibreSslCtx, verifyMode) == 48);
static_assert(offsetof(LibreSslCtx, defaultPasswdCallback) == 96);
static_assert(offsetof(LibreSslCtx, defaultPasswdCallbackUserdata) == 104);
static_assert(offsetof(LibreSslCtx, internal) == 112);
static_assert(offsetof(LibreSslCtx, extraCerts) == 40);
static_assert(offsetof(LibreSslCtx, sidCtxLength) == 52);
static_assert(offsetof(LibreSslCtx, sidCtx) == 56);
static_assert(offsetof(LibreSslCtxInternal, options) == 8);
static_assert(offsetof(LibreSslCtxInternal, mode) == 16);
static_assert(offsetof(LibreSslCtxInternal, msgCallback) == 96);
static_assert(offsetof(LibreSslCtxInternal, msgCallbackArg) == 104);
static_assert(offsetof(LibreSslCtxInternal, defaultVerifyCallback) == 112);
static_assert(offsetof(LibreSslCtxInternal, tlsextServernameCallback) == 128);
static_assert(offsetof(LibreSslCtxInternal, tlsextServernameArg) == 136);
static_assert(offsetof(LibreSslCtxInternal, tlsextTicketKeyCb) == 144);
static_assert(offsetof(LibreSslCtxInternal, tlsextStatusCb) == 152);
static_assert(offsetof(LibreSslCtxInternal, tlsextStatusArg) == 160);
static_assert(offsetof(LibreSslCtxInternal, sessionCacheSize) == 176);
static_assert(offsetof(LibreSslCtxInternal, sessionCacheMode) == 200);
static_assert(offsetof(LibreSslCtxInternal, sessConnect) == 204);
static_assert(offsetof(LibreSslCtxInternal, sessConnectRenegotiate) == 208);
static_assert(offsetof(LibreSslCtxInternal, sessConnectGood) == 212);
static_assert(offsetof(LibreSslCtxInternal, sessAccept) == 216);
static_assert(offsetof(LibreSslCtxInternal, sessAcceptRenegotiate) == 220);
static_assert(offsetof(LibreSslCtxInternal, sessAcceptGood) == 224);
static_assert(offsetof(LibreSslCtxInternal, sessMiss) == 228);
static_assert(offsetof(LibreSslCtxInternal, sessTimeout) == 232);
static_assert(offsetof(LibreSslCtxInternal, sessCacheFull) == 236);
static_assert(offsetof(LibreSslCtxInternal, sessHit) == 240);
static_assert(offsetof(LibreSslCtxInternal, sessCbHit) == 244);
static_assert(offsetof(LibreSslCtxInternal, maxCertList) == 280);
static_assert(offsetof(LibreSslCtxInternal, readAhead) == 288);
static_assert(offsetof(LibreSslCtxInternal, maxSendFragment) == 296);
static_assert(offsetof(LibreSslCtxInternal, tlsextTickKeyName) == 312);
static_assert(offsetof(LibreSslCtxInternal, tlsextTickHmacKey) == 328);
static_assert(offsetof(LibreSslCtxInternal, tlsextTickAesKey) == 344);
namespace {
enum Command : int {
NeedTmpRsa = 1,
SetTmpRsa = 2,
SetTmpDh = 3,
SetTmpEcdh = 4,
SetTmpRsaCb = 5,
SetTmpDhCb = 6,
SetTmpEcdhCb = 7,
ExtraChainCert = 14,
SetMsgCallback = 15,
SetMsgCallbackArg = 16,
SessNumber = 20,
SessConnect = 21,
SessConnectGood = 22,
SessConnectRenegotiate = 23,
SessAccept = 24,
SessAcceptGood = 25,
SessAcceptRenegotiate = 26,
SessHit = 27,
SessCbHit = 28,
SessMisses = 29,
SessTimeouts = 30,
SessCacheFull = 31,
Options = 32,
Mode = 33,
GetReadAhead = 40,
SetReadAhead = 41,
SetSessCacheSize = 42,
GetSessCacheSize = 43,
SetSessCacheMode = 44,
GetSessCacheMode = 45,
GetMaxCertList = 50,
SetMaxCertList = 51,
SetMaxSendFragment = 52,
SetTlsextServernameCb = 53,
SetTlsextServernameArg = 54,
GetTlsextTicketKeys = 58,
SetTlsextTicketKeys = 59,
SetTlsextStatusReqCb = 63,
SetTlsextStatusReqCbArg = 64,
SetTlsextTicketKeyCb = 72,
ClearOptions = 77,
ClearMode = 78,
GetExtraChainCerts = 82,
ClearExtraChainCerts = 83,
SetGroups = 91,
SetGroupsList = 92,
SetEcdhAuto = 94,
SetDhAuto = 118,
};
constexpr int ErrLibSsl = 20;
constexpr int ErrFunctionNone = 0xfff;
constexpr int ShouldNotHaveBeenCalled = 66;
constexpr int SessionIdContextTooLong = 273;
constexpr int InvalidTicketKeysLength = 325;
constexpr std::int64_t TicketKeysLength = 48;
constexpr std::int64_t MinSendFragment = 512;
constexpr std::int64_t MaxPlainLength = 16384;
LibreSslCtx& Context(LibreSslCtx* ctx, const char* function) {
if (!ctx) throw std::invalid_argument(std::string(function) + ": null context");
return *ctx;
}
LibreSslCtxInternal& Internal(LibreSslCtx* ctx, const char* function) {
LibreSslCtx& context = Context(ctx, function);
if (!context.internal) throw std::invalid_argument(std::string(function) + ": null internal state");
return *context.internal;
}
[[noreturn]] void UnsupportedCommand(const char* function, int cmd) {
NotImplemented_nid_no_patch((std::string(function) + " command " + std::to_string(cmd)).c_str());
}
void PutSslError(int reason) {
LibreSslPutError_nid_no_patch(ErrLibSsl, ErrFunctionNone, reason);
}
}
extern "C" {
@@ -47,4 +157,118 @@ void APS5_VABI SSL_CTX_set_default_passwd_cb_userdata_nid_postfix(LibreSslCtx* c
Context(ctx, __func__).defaultPasswdCallbackUserdata = userdata;
}
std::int64_t APS5_VABI SSL_CTX_ctrl_nid_postfix(LibreSslCtx* ctx, int cmd, std::int64_t larg, void* parg) {
LibreSslCtxInternal& internal = Internal(ctx, __func__);
switch (cmd) {
case GetReadAhead: return internal.readAhead;
case SetReadAhead: return std::exchange(internal.readAhead, static_cast<int>(larg));
case SetMsgCallbackArg: internal.msgCallbackArg = parg; return 1;
case GetMaxCertList: return internal.maxCertList;
case SetMaxCertList: return std::exchange(internal.maxCertList, larg);
case SetSessCacheSize: return static_cast<std::int64_t>(std::exchange(internal.sessionCacheSize, static_cast<std::uint64_t>(larg)));
case GetSessCacheSize: return static_cast<std::int64_t>(internal.sessionCacheSize);
case SetSessCacheMode: return std::exchange(internal.sessionCacheMode, static_cast<int>(larg));
case GetSessCacheMode: return internal.sessionCacheMode;
case SessConnect: return internal.sessConnect;
case SessConnectGood: return internal.sessConnectGood;
case SessConnectRenegotiate: return internal.sessConnectRenegotiate;
case SessAccept: return internal.sessAccept;
case SessAcceptGood: return internal.sessAcceptGood;
case SessAcceptRenegotiate: return internal.sessAcceptRenegotiate;
case SessHit: return internal.sessHit;
case SessCbHit: return internal.sessCbHit;
case SessMisses: return internal.sessMiss;
case SessTimeouts: return internal.sessTimeout;
case SessCacheFull: return internal.sessCacheFull;
case Options: return static_cast<std::int64_t>(internal.options |= static_cast<std::uint64_t>(larg));
case ClearOptions: return static_cast<std::int64_t>(internal.options &= ~static_cast<std::uint64_t>(larg));
case Mode: return static_cast<std::int64_t>(internal.mode |= static_cast<std::uint64_t>(larg));
case ClearMode: return static_cast<std::int64_t>(internal.mode &= ~static_cast<std::uint64_t>(larg));
case SetMaxSendFragment:
if (larg < MinSendFragment || larg > MaxPlainLength) return 0;
internal.maxSendFragment = static_cast<unsigned int>(larg);
return 1;
case NeedTmpRsa: return 0;
case SetTmpRsa:
case SetTmpRsaCb:
case SetTmpDhCb:
case SetTmpEcdhCb:
PutSslError(ShouldNotHaveBeenCalled);
return 0;
case SetTlsextServernameArg: internal.tlsextServernameArg = parg; return 1;
case GetTlsextTicketKeys:
case SetTlsextTicketKeys: {
auto* keys = static_cast<unsigned char*>(parg);
if (!keys) return TicketKeysLength;
if (larg != TicketKeysLength) {
PutSslError(InvalidTicketKeysLength);
return 0;
}
if (cmd == SetTlsextTicketKeys) {
std::memcpy(internal.tlsextTickKeyName, keys, 16);
std::memcpy(internal.tlsextTickHmacKey, keys + 16, 16);
std::memcpy(internal.tlsextTickAesKey, keys + 32, 16);
} else {
std::memcpy(keys, internal.tlsextTickKeyName, 16);
std::memcpy(keys + 16, internal.tlsextTickHmacKey, 16);
std::memcpy(keys + 32, internal.tlsextTickAesKey, 16);
}
return 1;
}
case SetTlsextStatusReqCbArg: internal.tlsextStatusArg = parg; return 1;
case GetExtraChainCerts:
if (!parg) throw std::invalid_argument(std::string(__func__) + ": null extra chain certificates output");
*static_cast<void**>(parg) = ctx->extraCerts;
return 1;
case SetTmpDh:
case SetTmpEcdh:
case ExtraChainCert:
case SessNumber:
case ClearExtraChainCerts:
case SetGroups:
case SetGroupsList:
case SetEcdhAuto:
case SetDhAuto: UnsupportedCommand(__func__, cmd);
default: return 0;
}
}
std::int64_t APS5_VABI SSL_CTX_callback_ctrl_nid_postfix(LibreSslCtx* ctx, int cmd, void* callback) {
LibreSslCtxInternal& internal = Internal(ctx, __func__);
switch (cmd) {
case SetMsgCallback: internal.msgCallback = callback; return 1;
case SetTmpRsaCb:
PutSslError(ShouldNotHaveBeenCalled);
return 0;
case SetTmpDhCb:
case SetTmpEcdhCb: UnsupportedCommand(__func__, cmd);
case SetTlsextServernameCb: internal.tlsextServernameCallback = callback; return 1;
case SetTlsextStatusReqCb: internal.tlsextStatusCb = callback; return 1;
case SetTlsextTicketKeyCb: internal.tlsextTicketKeyCb = callback; return 1;
default: return 0;
}
}
void APS5_VABI SSL_CTX_set_msg_callback_nid_postfix(LibreSslCtx* ctx, void* callback) {
Internal(ctx, __func__).msgCallback = callback;
}
void APS5_VABI SSL_CTX_set_verify_nid_postfix(LibreSslCtx* ctx, int mode, void* callback) {
LibreSslCtxInternal& internal = Internal(ctx, __func__);
ctx->verifyMode = mode;
internal.defaultVerifyCallback = callback;
}
int APS5_VABI SSL_CTX_set_session_id_context_nid_postfix(LibreSslCtx* ctx, const unsigned char* sidCtx, unsigned int length) {
LibreSslCtx& context = Context(ctx, __func__);
if (length > sizeof context.sidCtx) {
PutSslError(SessionIdContextTooLong);
return 0;
}
if (!sidCtx && length) throw std::invalid_argument(std::string(__func__) + ": null session id context");
context.sidCtxLength = length;
std::copy_n(sidCtx, length, context.sidCtx);
return 1;
}
}
@@ -0,0 +1,442 @@
#include "prx/libSceLibreSsl/include/Api.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <source_location>
#include <stdexcept>
constexpr std::size_t CtxSize = 120;
constexpr std::size_t InternalSize = 464;
constexpr std::size_t CtxExtraCerts = 40;
constexpr std::size_t CtxVerifyMode = 48;
constexpr std::size_t CtxSidCtxLength = 52;
constexpr std::size_t CtxSidCtx = 56;
constexpr std::size_t CtxInternal = 112;
constexpr std::size_t MinVersion = 0;
constexpr std::size_t MaxVersion = 2;
constexpr std::size_t Options = 8;
constexpr std::size_t Mode = 16;
constexpr std::size_t MsgCallback = 96;
constexpr std::size_t MsgCallbackArg = 104;
constexpr std::size_t DefaultVerifyCallback = 112;
constexpr std::size_t ServernameCallback = 128;
constexpr std::size_t ServernameArg = 136;
constexpr std::size_t TicketKeyCallback = 144;
constexpr std::size_t StatusCallback = 152;
constexpr std::size_t StatusArg = 160;
constexpr std::size_t SessionCacheSize = 176;
constexpr std::size_t SessionCacheMode = 200;
constexpr std::size_t StatsConnect = 204;
constexpr std::size_t StatsConnectRenegotiate = 208;
constexpr std::size_t StatsConnectGood = 212;
constexpr std::size_t StatsAccept = 216;
constexpr std::size_t StatsAcceptRenegotiate = 220;
constexpr std::size_t StatsAcceptGood = 224;
constexpr std::size_t StatsMiss = 228;
constexpr std::size_t StatsTimeout = 232;
constexpr std::size_t StatsCacheFull = 236;
constexpr std::size_t StatsHit = 240;
constexpr std::size_t StatsCbHit = 244;
constexpr std::size_t MaxCertList = 280;
constexpr std::size_t ReadAhead = 288;
constexpr std::size_t MaxSendFragment = 296;
constexpr std::size_t TicketKeys = 312;
constexpr std::uint64_t ShouldNotHaveBeenCalled = 0x14FFF042;
constexpr std::uint64_t InvalidTicketKeysLength = 0x14FFF145;
constexpr std::uint64_t SessionIdContextTooLong = 0x14FFF111;
static_assert(sizeof(LibreSslCtx) == CtxSize && sizeof(LibreSslCtxInternal) == InternalSize);
static_assert(StatsCbHit + 4 == 248 && TicketKeys + 48 == 360 && CtxSidCtx + 32 == 88);
static void Require(bool condition, std::source_location location = std::source_location::current()) {
if (condition) return;
std::fprintf(stderr, "LibreSSL SSL_CTX fields 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* Pointer(std::uintptr_t value) {
return reinterpret_cast<void*>(value);
}
template<typename TValue> static void Store(unsigned char* base, std::size_t offset, TValue value) {
std::memcpy(base + offset, &value, sizeof value);
}
template<typename TValue> static TValue Load(const unsigned char* base, std::size_t offset) {
TValue value;
std::memcpy(&value, base + offset, sizeof value);
return value;
}
struct Bytes {
alignas(8) unsigned char ctx[CtxSize];
alignas(8) unsigned char internal[InternalSize];
};
struct Fixture {
Bytes actual;
Bytes expected;
Fixture() {
for (std::size_t i = 0; i < CtxSize; ++i) actual.ctx[i] = static_cast<unsigned char>(i * 7 + 3);
for (std::size_t i = 0; i < InternalSize; ++i) actual.internal[i] = static_cast<unsigned char>(i * 13 + 5);
Store<void*>(actual.ctx, CtxExtraCerts, nullptr);
Store<int>(actual.ctx, CtxVerifyMode, 0);
Store<unsigned int>(actual.ctx, CtxSidCtxLength, 0);
Store<void*>(actual.ctx, CtxInternal, actual.internal);
Store<std::uint16_t>(actual.internal, MinVersion, 0x301);
Store<std::uint16_t>(actual.internal, MaxVersion, 0x303);
Store<std::uint64_t>(actual.internal, Options, 0x4);
Store<std::uint64_t>(actual.internal, Mode, 0);
for (std::size_t offset : {MsgCallback, MsgCallbackArg, DefaultVerifyCallback, ServernameCallback, ServernameArg, TicketKeyCallback, StatusCallback, StatusArg})
Store<void*>(actual.internal, offset, nullptr);
Store<std::uint64_t>(actual.internal, SessionCacheSize, 20480);
Store<int>(actual.internal, SessionCacheMode, 2);
for (std::size_t offset = StatsConnect; offset <= StatsCbHit; offset += 4) Store<int>(actual.internal, offset, 0);
Store<std::int64_t>(actual.internal, MaxCertList, 102400);
Store<int>(actual.internal, ReadAhead, 0);
Store<unsigned int>(actual.internal, MaxSendFragment, 16384);
expected = actual;
}
Fixture(const Fixture&) = delete;
Fixture& operator=(const Fixture&) = delete;
LibreSslCtx* Context() {
return reinterpret_cast<LibreSslCtx*>(actual.ctx);
}
template<typename TValue> void SetCtx(std::size_t offset, TValue value) {
Store(actual.ctx, offset, value);
Store(expected.ctx, offset, value);
}
template<typename TValue> void SetInternal(std::size_t offset, TValue value) {
Store(actual.internal, offset, value);
Store(expected.internal, offset, value);
}
template<typename TValue> void ExpectCtx(std::size_t offset, TValue value) {
Store(expected.ctx, offset, value);
}
template<typename TValue> void ExpectInternal(std::size_t offset, TValue value) {
Store(expected.internal, offset, value);
}
void Verify(std::uint64_t error, std::source_location location) {
Require(std::memcmp(actual.ctx, expected.ctx, CtxSize) == 0, location);
Require(std::memcmp(actual.internal, expected.internal, InternalSize) == 0, location);
Require(ERR_get_error_nid_postfix() == error, location);
Require(ERR_get_error_nid_postfix() == 0, location);
}
void Ctrl(int cmd, std::int64_t larg, void* parg, std::int64_t result, std::uint64_t error = 0, std::source_location location = std::source_location::current()) {
Require(SSL_CTX_ctrl_nid_postfix(Context(), cmd, larg, parg) == result, location);
Verify(error, location);
}
void CallbackCtrl(int cmd, void* callback, std::int64_t result, std::uint64_t error = 0, std::source_location location = std::source_location::current()) {
Require(SSL_CTX_callback_ctrl_nid_postfix(Context(), cmd, callback) == result, location);
Verify(error, location);
}
void SessionIdContext(const unsigned char* sidCtx, unsigned int length, int result, std::uint64_t error = 0, std::source_location location = std::source_location::current()) {
Require(SSL_CTX_set_session_id_context_nid_postfix(Context(), sidCtx, length) == result, location);
Verify(error, location);
}
template<typename TAction> void Throws(TAction action, std::source_location location = std::source_location::current()) {
RequireThrows(action, location);
Verify(0, location);
}
};
static void TestOptionsAndMode() {
Fixture f;
f.Ctrl(32, 0x4, nullptr, 0x4);
f.ExpectInternal<std::uint64_t>(Options, 0x80000004);
f.Ctrl(32, 0x80000000, nullptr, 0x80000004);
f.ExpectInternal<std::uint64_t>(Options, 0x80000000);
f.Ctrl(77, 0x4, nullptr, 0x80000000);
f.ExpectInternal<std::uint64_t>(Mode, 0x2);
f.Ctrl(33, 0x2, nullptr, 0x2);
f.ExpectInternal<std::uint64_t>(Mode, 0);
f.Ctrl(78, 0x2, nullptr, 0);
f.ExpectInternal<std::uint64_t>(Options, UINT64_MAX);
f.Ctrl(32, -1, nullptr, -1);
f.ExpectInternal<std::uint64_t>(Options, 0);
f.Ctrl(77, -1, nullptr, 0);
f.ExpectInternal<std::uint64_t>(Mode, UINT64_MAX);
f.Ctrl(33, -1, nullptr, -1);
f.ExpectInternal<std::uint64_t>(Mode, 0x8000000000000000);
f.Ctrl(78, INT64_MAX, nullptr, INT64_MIN);
}
static void TestReadAhead() {
Fixture f;
f.Ctrl(40, 0, nullptr, 0);
f.ExpectInternal<int>(ReadAhead, 1);
f.Ctrl(41, 1, nullptr, 0);
f.Ctrl(41, 0x100000001, nullptr, 1);
f.Ctrl(40, 0, nullptr, 1);
f.ExpectInternal<int>(ReadAhead, 0);
f.Ctrl(41, 0x100000000, nullptr, 1);
f.Ctrl(40, 0, nullptr, 0);
f.ExpectInternal<int>(ReadAhead, -1);
f.Ctrl(41, -1, nullptr, 0);
f.Ctrl(40, 0, nullptr, -1);
}
static void TestMaxCertList() {
Fixture f;
f.Ctrl(50, 0, nullptr, 102400);
f.ExpectInternal<std::int64_t>(MaxCertList, 1234);
f.Ctrl(51, 1234, nullptr, 102400);
f.ExpectInternal<std::int64_t>(MaxCertList, -5);
f.Ctrl(51, -5, nullptr, 1234);
f.Ctrl(50, 0, nullptr, -5);
}
static void TestSessionCache() {
Fixture f;
f.Ctrl(43, 0, nullptr, 20480);
f.ExpectInternal<std::uint64_t>(SessionCacheSize, 7);
f.Ctrl(42, 7, nullptr, 20480);
f.ExpectInternal<std::uint64_t>(SessionCacheSize, UINT64_MAX);
f.Ctrl(42, -1, nullptr, 7);
f.Ctrl(43, 0, nullptr, -1);
f.Ctrl(45, 0, nullptr, 2);
f.ExpectInternal<int>(SessionCacheMode, 3);
f.Ctrl(44, 3, nullptr, 2);
f.ExpectInternal<int>(SessionCacheMode, 2);
f.Ctrl(44, 0x100000002, nullptr, 3);
f.Ctrl(45, 0, nullptr, 2);
}
static void TestMaxSendFragment() {
Fixture f;
f.Ctrl(52, 511, nullptr, 0);
f.ExpectInternal<unsigned int>(MaxSendFragment, 512);
f.Ctrl(52, 512, nullptr, 1);
f.ExpectInternal<unsigned int>(MaxSendFragment, 16384);
f.Ctrl(52, 16384, nullptr, 1);
f.Ctrl(52, 16385, nullptr, 0);
f.Ctrl(52, -1, nullptr, 0);
f.Ctrl(52, 0x100000200, nullptr, 0);
}
static void TestStats() {
Fixture f;
for (int cmd = 21; cmd <= 31; ++cmd) f.Ctrl(cmd, 0, nullptr, 0);
const std::size_t offsets[] = {StatsConnect, StatsConnectRenegotiate, StatsConnectGood, StatsAccept, StatsAcceptRenegotiate, StatsAcceptGood,
StatsMiss, StatsTimeout, StatsCacheFull, StatsHit, StatsCbHit};
for (int i = 0; i < 11; ++i) f.SetInternal<int>(offsets[i], 101 + i);
f.Ctrl(21, 0, nullptr, 101);
f.Ctrl(22, 0, nullptr, 103);
f.Ctrl(23, 0, nullptr, 102);
f.Ctrl(24, 0, nullptr, 104);
f.Ctrl(25, 0, nullptr, 106);
f.Ctrl(26, 0, nullptr, 105);
f.Ctrl(27, 0, nullptr, 110);
f.Ctrl(28, 0, nullptr, 111);
f.Ctrl(29, 0, nullptr, 107);
f.Ctrl(30, 0, nullptr, 108);
f.Ctrl(31, 0, nullptr, 109);
f.SetInternal<int>(StatsConnect, -1);
f.Ctrl(21, 0, nullptr, -1);
}
static void TestCallbackArgs() {
Fixture f;
f.ExpectInternal<void*>(MsgCallbackArg, Pointer(0x2222));
f.Ctrl(16, 0, Pointer(0x2222), 1);
f.ExpectInternal<void*>(ServernameArg, Pointer(0x3333));
f.Ctrl(54, 0, Pointer(0x3333), 1);
f.ExpectInternal<void*>(StatusArg, Pointer(0x4444));
f.Ctrl(64, 0, Pointer(0x4444), 1);
f.ExpectInternal<void*>(MsgCallbackArg, nullptr);
f.Ctrl(16, 5, nullptr, 1);
}
static void TestTicketKeys() {
Fixture f;
f.Ctrl(58, 0, nullptr, 48);
f.Ctrl(59, 0, nullptr, 48);
f.Ctrl(58, 47, nullptr, 48);
f.Ctrl(59, 47, nullptr, 48);
unsigned char buffer[48];
std::memset(buffer, 0xee, sizeof buffer);
f.Ctrl(58, 47, buffer, 0, InvalidTicketKeysLength);
for (unsigned char byte : buffer) Require(byte == 0xee);
f.Ctrl(59, 47, buffer, 0, InvalidTicketKeysLength);
f.Ctrl(59, 49, buffer, 0, InvalidTicketKeysLength);
f.Ctrl(58, 48, buffer, 1);
Require(std::memcmp(buffer, f.actual.internal + TicketKeys, 48) == 0);
for (int i = 0; i < 48; ++i) buffer[i] = static_cast<unsigned char>(i);
for (int i = 0; i < 48; ++i) f.ExpectInternal<unsigned char>(TicketKeys + i, static_cast<unsigned char>(i));
f.Ctrl(59, 48, buffer, 1);
unsigned char keys[48];
std::memset(keys, 0xee, sizeof keys);
f.Ctrl(58, 48, keys, 1);
for (int i = 0; i < 48; ++i) Require(keys[i] == i);
}
static void TestExtraChainCerts() {
Fixture f;
void* slot = Pointer(0x5555);
f.Ctrl(82, 0, &slot, 1);
Require(slot == nullptr);
f.SetCtx<void*>(CtxExtraCerts, Pointer(0x7777));
f.Ctrl(82, 0, &slot, 1);
Require(slot == Pointer(0x7777));
f.Throws([&] { SSL_CTX_ctrl_nid_postfix(f.Context(), 82, 0, nullptr); });
}
static void TestTemporaryKeys() {
Fixture f;
f.Ctrl(1, 0, nullptr, 0);
f.Ctrl(2, 0, nullptr, 0, ShouldNotHaveBeenCalled);
f.Ctrl(5, 0, nullptr, 0, ShouldNotHaveBeenCalled);
f.Ctrl(6, 0, nullptr, 0, ShouldNotHaveBeenCalled);
f.Ctrl(7, 0, nullptr, 0, ShouldNotHaveBeenCalled);
}
static void TestOtherCtrlCommands() {
Fixture f;
for (int cmd : {0, 8, 13, 15, 17, 55, 65, 999, -1}) f.Ctrl(cmd, 0, nullptr, 0);
for (int cmd : {3, 4, 14, 20, 83, 91, 92, 94, 118}) f.Throws([&] { SSL_CTX_ctrl_nid_postfix(f.Context(), cmd, 0, Pointer(0x1111)); });
}
static void TestCallbackCtrl() {
Fixture f;
f.ExpectInternal<void*>(MsgCallback, Pointer(0x6666));
f.CallbackCtrl(15, Pointer(0x6666), 1);
f.ExpectInternal<void*>(ServernameCallback, Pointer(0x7777));
f.CallbackCtrl(53, Pointer(0x7777), 1);
f.ExpectInternal<void*>(StatusCallback, Pointer(0x8888));
f.CallbackCtrl(63, Pointer(0x8888), 1);
f.ExpectInternal<void*>(TicketKeyCallback, Pointer(0x9999));
f.CallbackCtrl(72, Pointer(0x9999), 1);
f.CallbackCtrl(5, Pointer(0x1111), 0, ShouldNotHaveBeenCalled);
f.CallbackCtrl(0, Pointer(0x1111), 0);
f.CallbackCtrl(16, Pointer(0x1111), 0);
f.CallbackCtrl(999, Pointer(0x1111), 0);
for (int cmd : {6, 7}) f.Throws([&] { SSL_CTX_callback_ctrl_nid_postfix(f.Context(), cmd, Pointer(0x1111)); });
}
static void TestSetMsgCallback() {
Fixture f;
f.ExpectInternal<void*>(MsgCallback, Pointer(0xaaaa));
SSL_CTX_set_msg_callback_nid_postfix(f.Context(), Pointer(0xaaaa));
f.Verify(0, std::source_location::current());
f.ExpectInternal<void*>(MsgCallback, nullptr);
SSL_CTX_set_msg_callback_nid_postfix(f.Context(), nullptr);
f.Verify(0, std::source_location::current());
}
static void TestSetVerify() {
Fixture f;
f.ExpectCtx<int>(CtxVerifyMode, 3);
f.ExpectInternal<void*>(DefaultVerifyCallback, Pointer(0xbbbb));
SSL_CTX_set_verify_nid_postfix(f.Context(), 3, Pointer(0xbbbb));
f.Verify(0, std::source_location::current());
f.ExpectCtx<int>(CtxVerifyMode, -1);
f.ExpectInternal<void*>(DefaultVerifyCallback, nullptr);
SSL_CTX_set_verify_nid_postfix(f.Context(), -1, nullptr);
f.Verify(0, std::source_location::current());
f.ExpectCtx<int>(CtxVerifyMode, 0x7fffffff);
f.ExpectInternal<void*>(DefaultVerifyCallback, Pointer(0xcccc));
SSL_CTX_set_verify_nid_postfix(f.Context(), 0x7fffffff, Pointer(0xcccc));
f.Verify(0, std::source_location::current());
}
static void TestSetSessionIdContext() {
Fixture f;
const unsigned char abc[] = {'a', 'b', 'c'};
unsigned char sequence[33];
for (int i = 0; i < 33; ++i) sequence[i] = static_cast<unsigned char>(i + 1);
const unsigned char q[] = {'q'};
const unsigned char zz[] = {'z', 'z'};
f.ExpectCtx<unsigned int>(CtxSidCtxLength, 3);
for (int i = 0; i < 3; ++i) f.ExpectCtx<unsigned char>(CtxSidCtx + i, abc[i]);
f.SessionIdContext(abc, 3, 1);
f.ExpectCtx<unsigned int>(CtxSidCtxLength, 32);
for (int i = 0; i < 32; ++i) f.ExpectCtx<unsigned char>(CtxSidCtx + i, sequence[i]);
f.SessionIdContext(sequence, 32, 1);
f.SessionIdContext(sequence, 33, 0, SessionIdContextTooLong);
f.SessionIdContext(sequence, UINT32_MAX, 0, SessionIdContextTooLong);
f.SessionIdContext(nullptr, 33, 0, SessionIdContextTooLong);
f.ExpectCtx<unsigned int>(CtxSidCtxLength, 0);
f.SessionIdContext(q, 0, 1);
f.SessionIdContext(nullptr, 0, 1);
f.ExpectCtx<unsigned int>(CtxSidCtxLength, 32);
f.SessionIdContext(sequence, 32, 1);
f.ExpectCtx<unsigned int>(CtxSidCtxLength, 2);
f.ExpectCtx<unsigned char>(CtxSidCtx, 'z');
f.ExpectCtx<unsigned char>(CtxSidCtx + 1, 'z');
f.SessionIdContext(zz, 2, 1);
for (int i = 2; i < 32; ++i) Require(f.actual.ctx[CtxSidCtx + i] == i + 1);
f.Throws([&] { SSL_CTX_set_session_id_context_nid_postfix(f.Context(), nullptr, 1); });
}
static void TestNullContext() {
const unsigned char sidCtx[] = {1};
RequireThrows([] { SSL_CTX_ctrl_nid_postfix(nullptr, 32, 1, nullptr); });
RequireThrows([] { SSL_CTX_callback_ctrl_nid_postfix(nullptr, 15, nullptr); });
RequireThrows([] { SSL_CTX_set_msg_callback_nid_postfix(nullptr, nullptr); });
RequireThrows([] { SSL_CTX_set_verify_nid_postfix(nullptr, 1, nullptr); });
RequireThrows([&] { SSL_CTX_set_session_id_context_nid_postfix(nullptr, sidCtx, 1); });
Require(ERR_get_error_nid_postfix() == 0);
}
static void TestNullInternal() {
Fixture f;
f.SetCtx<void*>(CtxInternal, nullptr);
unsigned char keys[48] {};
for (int cmd = -1; cmd <= 120; ++cmd) {
f.Throws([&] { SSL_CTX_ctrl_nid_postfix(f.Context(), cmd, 48, keys); });
f.Throws([&] { SSL_CTX_callback_ctrl_nid_postfix(f.Context(), cmd, Pointer(0x1111)); });
}
f.Throws([&] { SSL_CTX_ctrl_nid_postfix(f.Context(), 999, 0, nullptr); });
f.Throws([&] { SSL_CTX_callback_ctrl_nid_postfix(f.Context(), 999, nullptr); });
f.Throws([&] { SSL_CTX_set_msg_callback_nid_postfix(f.Context(), Pointer(0xaaaa)); });
f.Throws([&] { SSL_CTX_set_verify_nid_postfix(f.Context(), 3, Pointer(0xbbbb)); });
const unsigned char abc[] = {'a', 'b', 'c'};
f.ExpectCtx<unsigned int>(CtxSidCtxLength, 3);
for (int i = 0; i < 3; ++i) f.ExpectCtx<unsigned char>(CtxSidCtx + i, abc[i]);
f.SessionIdContext(abc, 3, 1);
}
int main() {
ERR_clear_error_nid_postfix();
TestOptionsAndMode();
TestReadAhead();
TestMaxCertList();
TestSessionCache();
TestMaxSendFragment();
TestStats();
TestCallbackArgs();
TestTicketKeys();
TestExtraChainCerts();
TestTemporaryKeys();
TestOtherCtrlCommands();
TestCallbackCtrl();
TestSetMsgCallback();
TestSetVerify();
TestSetSessionIdContext();
TestNullContext();
TestNullInternal();
return 0;
}
+3 -2
View File
@@ -2,17 +2,18 @@
### Unknown function info
- [libSceLibreSsl pending exports](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - 337 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) - 332 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.
- [RAND_add, RAND_bytes, RAND_status, RAND_load_file, RAND_file_name, CRYPTO_malloc, CRYPTO_free, CRYPTO_set_mem_functions](../../../core/libs/prx/libSceLibreSsl/src/Runtime.cpp) (libSceLibreSsl) - follow LibreSSL's [rand_lib.c, randfile.c](https://github.com/libressl/openbsd/tree/0f0b16dc977f6ca499f0f4540078d992c96da597/src/lib/libcrypto/rand) and [malloc-wrapper.c](https://github.com/libressl/openbsd/blob/0f0b16dc977f6ca499f0f4540078d992c96da597/src/lib/libcrypto/malloc-wrapper.c), which are the same in 2.6.5 (3.4.3 linked); nothing is checked on the console. `RAND_bytes` reads host entropy and `CRYPTO_malloc` and `CRYPTO_free` use the guest heap. `CRYPTO_malloc` returns null for a size of zero or less, as LibreSSL 2.5.4 to 3.4 do; later versions take a `size_t` size and call `malloc`. A null buffer with a positive length throws
- [AES_set_encrypt_key, AES_set_decrypt_key, AES_encrypt, AES_decrypt, AES_ecb_encrypt, AES_cbc_encrypt, AES_cfb128_encrypt, AES_ctr128_encrypt](../../../core/libs/prx/libSceLibreSsl/src/Aes.cpp) (libSceLibreSsl) - follow LibreSSL's [aes.h](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/aes/aes.h) and [mode code](https://github.com/libressl/openbsd/tree/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/modes). Nothing is checked on the console. Key setup follows [LibreSSL 2.5.4's aes_core.c](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto/aes/aes_core.c), the version the `X509_verify_cert_error_string` entry names: a null pointer returns -1 and a key length other than 128, 192 or 256 bits returns -2 before the key is written, and only the 44, 52 or 60 words the key length needs are written. The `AES_KEY` schedule uses that file's generic C layout (big-endian words, `rounds` 10, 12 or 14). The 2.5.4 amd64 build uses [aes-x86_64](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto/aes/asm/aes-x86_64.pl) instead, which copies the key bytes without swapping, so each word is byte-reversed compared with the C layout (OpenSSL 3.0.13's x86-64 code gives the same schedules byte-reversed); the console's build options are unknown, so a schedule the title reads or fills is unverified. CTR leaves the last keystream block in `ecount_buf` even at a block boundary. Null pointers in the cipher and mode functions, other `rounds` values and a CFB or CTR position outside 0-15 throw
- [ERR_get_error, ERR_peek_error, ERR_clear_error, ERR_remove_thread_state](../../../core/libs/prx/libSceLibreSsl/src/Error.cpp) (libSceLibreSsl) - no export of this library adds an error yet, so the queue stays empty for guest code. The per-thread queue of 16 slots holding 15 codes, its order and the `ERR_PACK` layout follow LibreSSL's [err.c](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/err/err.c) and [err.h](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/err/err.h); the module's LibreSSL version is unknown and nothing is checked on the console. The queue keeps no file, line or data, as no export reads them. `ERR_remove_thread_state` with a thread id throws: that version asserts a null id, while older versions remove the state of the thread the id names
- [ERR_get_error, ERR_peek_error, ERR_clear_error, ERR_remove_thread_state](../../../core/libs/prx/libSceLibreSsl/src/Error.cpp) (libSceLibreSsl) - the per-thread queue of 16 slots holding 15 codes, its order and the `ERR_PACK` layout follow LibreSSL's [err.c](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/err/err.c) and [err.h](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/err/err.h); the module's LibreSSL version is unknown and nothing is checked on the console. The queue keeps no file, line or data, as no export reads them. `ERR_remove_thread_state` with a thread id throws: that version asserts a null id, while older versions remove the state of the thread the id names
- [OCSP_response_status_str, OCSP_cert_status_str and OCSP_crl_reason_str](../../../core/libs/prx/libSceLibreSsl/src/Ocsp.cpp) (libSceLibreSsl) - the module's strings are not measured on the console. The tables follow LibreSSL [ocsp_prn.c](https://github.com/libressl/openbsd/blob/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libcrypto/ocsp/ocsp_prn.c), unchanged from revision 1.8 (2015) to 1.12 (2025), with codes from `ocsp.h`; the argument is a 64-bit `long` and every value not in a table returns `(UNKNOWN)`
- [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.
- [SSL_CTX_get_verify_mode, SSL_CTX_get_cert_store, SSL_CTX_set_quiet_shutdown, SSL_CTX_set_default_passwd_cb, SSL_CTX_set_default_passwd_cb_userdata](../../../core/libs/prx/libSceLibreSsl/src/SslCtx.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/libssl) `ssl.h`, `ssl_locl.h` and `ssl_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 context yet, so only contexts the caller builds reach them, and no export calls the stored password callback. A null context, and a null internal state in `SSL_CTX_set_quiet_shutdown`, which LibreSSL dereferences, throw
- [SSL_CTX_ctrl, SSL_CTX_callback_ctrl, SSL_CTX_set_msg_callback, SSL_CTX_set_verify, SSL_CTX_set_session_id_context](../../../core/libs/prx/libSceLibreSsl/src/SslCtx.cpp) (libSceLibreSsl) - nothing is checked on the console. The internal layout, commands and results follow [LibreSSL 2.5.4](https://github.com/libressl/openbsd/tree/2e2c612066aa993717528a0249c15c51128d61cb/src/lib/libssl) `ssl_locl.h`, `ssl_lib.c` and `s3_lib.c`, the version in the [firmware 13.40 measurements](https://github.com/boykopovar/AnyPS5/discussions/8981#discussioncomment-19111214). Control commands 3, 4, 14, 20, 83, 91, 92, 94 and 118 and callback commands 6 and 7 throw for every input, as they use certificate, session table, DH, ECDH, stack or group state that no export builds yet. Commands outside 2.5.4's switch return 0, as in that release. A null context, a null internal state, a null output for command 82 and a null session ID context with a nonzero length throw
### Functional