Files
AnyPS5/core/libs/tests/GuestLibreSslSslSettings.cpp
T

428 lines
17 KiB
C++

#include "prx/libSceLibreSsl/include/Api.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <source_location>
#include <stdexcept>
struct TestSslInternal {
unsigned char beforeOptions[8];
std::uint64_t options;
std::uint64_t mode;
unsigned char beforeHandshakeFunc[32];
void* handshakeFunc;
void* msgCallback;
void* msgCallbackArg;
unsigned char beforeVerifyCallback[8];
void* verifyCallback;
unsigned char beforeShutdown[72];
int shutdown;
unsigned char beforeReadAhead[40];
int readAhead;
unsigned char beforeAeadReadCtx[24];
void* aeadReadCtx;
void* aeadWriteCtx;
void* encWriteCtx;
void* writeHash;
unsigned char beforeMaxCertList[24];
std::int64_t maxCertList;
unsigned char beforeState[108];
int state;
int rstate;
unsigned char rest[12];
};
struct TestSsl3Internal {
unsigned char beforeSendConnectionBinding[1012];
int sendConnectionBinding;
unsigned char beforeAlpnSelected[8];
const unsigned char* alpnSelected;
unsigned int alpnSelectedLength;
unsigned char rest[4];
};
struct TestSsl3 {
unsigned char beforeInternal[136];
TestSsl3Internal* internal;
};
struct TestDtls1Internal {
unsigned char beforeMtu[636];
std::uint32_t mtu;
unsigned char rest[4];
};
struct TestDtls1 {
unsigned char beforeInternal[32];
TestDtls1Internal* internal;
};
struct TestMethodInternal {
int version;
unsigned char beforeAccept[28];
void* accept;
void* connect;
unsigned char rest[112];
};
struct TestMethod {
unsigned char beforeInternal[40];
TestMethodInternal* internal;
};
struct TestSsl {
int version;
unsigned char beforeMethod[4];
TestMethod* method;
unsigned char beforeServer[24];
int server;
unsigned char beforeS3[4];
TestSsl3* s3;
TestDtls1* d1;
unsigned char beforeVerifyMode[72];
int verifyMode;
unsigned char beforeClientVersion[32];
int clientVersion;
unsigned int maxSendFragment;
unsigned char beforeTlsextHostname[4];
char* tlsextHostname;
unsigned char beforeEncReadCtx[16];
void* encReadCtx;
void* readHash;
TestSslInternal* internal;
};
static_assert(sizeof(TestSslInternal) == 432 && offsetof(TestSslInternal, options) == 8 && offsetof(TestSslInternal, mode) == 16);
static_assert(offsetof(TestSslInternal, handshakeFunc) == 56 && offsetof(TestSslInternal, msgCallback) == 64 && offsetof(TestSslInternal, msgCallbackArg) == 72);
static_assert(offsetof(TestSslInternal, verifyCallback) == 88 && offsetof(TestSslInternal, shutdown) == 168 && offsetof(TestSslInternal, readAhead) == 212);
static_assert(offsetof(TestSslInternal, aeadReadCtx) == 240 && offsetof(TestSslInternal, aeadWriteCtx) == 248 && offsetof(TestSslInternal, encWriteCtx) == 256);
static_assert(offsetof(TestSslInternal, writeHash) == 264 && offsetof(TestSslInternal, maxCertList) == 296);
static_assert(offsetof(TestSslInternal, state) == 412 && offsetof(TestSslInternal, rstate) == 416);
static_assert(sizeof(TestSsl3Internal) == 1040 && offsetof(TestSsl3Internal, sendConnectionBinding) == 1012);
static_assert(offsetof(TestSsl3Internal, alpnSelected) == 1024 && offsetof(TestSsl3Internal, alpnSelectedLength) == 1032);
static_assert(sizeof(TestSsl3) == 144 && sizeof(TestDtls1) == 40 && offsetof(TestDtls1Internal, mtu) == 636);
static_assert(sizeof(TestMethodInternal) == 160 && offsetof(TestMethodInternal, accept) == 32 && offsetof(TestMethodInternal, connect) == 40);
static_assert(sizeof(TestMethod) == 48 && sizeof(TestSsl) == 232 && offsetof(TestSsl, method) == 8 && offsetof(TestSsl, server) == 40);
static_assert(offsetof(TestSsl, s3) == 48 && offsetof(TestSsl, d1) == 56 && offsetof(TestSsl, verifyMode) == 136);
static_assert(offsetof(TestSsl, clientVersion) == 172 && offsetof(TestSsl, maxSendFragment) == 176 && offsetof(TestSsl, tlsextHostname) == 184);
static_assert(offsetof(TestSsl, encReadCtx) == 208 && offsetof(TestSsl, readHash) == 216 && offsetof(TestSsl, internal) == 224);
static void Require(bool condition, std::source_location location = std::source_location::current()) {
if (condition) return;
std::fprintf(stderr, "LibreSSL SSL settings 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);
}
template<typename T> static void Fill(T& value, unsigned char seed) {
auto* bytes = reinterpret_cast<unsigned char*>(&value);
for (std::size_t index = 0; index < sizeof(T); ++index) bytes[index] = static_cast<unsigned char>(seed + index);
}
template<typename T> static bool Same(const T& left, const T& right) {
return std::memcmp(&left, &right, sizeof(T)) == 0;
}
struct Connection {
TestSsl ssl;
TestSslInternal internal;
Connection() {
Fill(ssl, 0x10);
Fill(internal, 0x40);
ssl.method = nullptr;
ssl.s3 = nullptr;
ssl.d1 = nullptr;
ssl.encReadCtx = nullptr;
ssl.readHash = nullptr;
ssl.internal = &internal;
internal.aeadReadCtx = nullptr;
internal.aeadWriteCtx = nullptr;
internal.encWriteCtx = nullptr;
internal.writeHash = nullptr;
}
LibreSslSsl* Ssl() {
return reinterpret_cast<LibreSslSsl*>(&ssl);
}
};
static std::int64_t Control(Connection& connection, int command, std::int64_t argument, void* pointer = nullptr) {
return SSL_ctrl_nid_postfix(connection.Ssl(), command, argument, pointer);
}
static void TestSetVerify() {
int first = 0;
int second = 0;
Connection connection;
Connection expected = connection;
RequireThrows([&] { SSL_set_verify_nid_postfix(nullptr, 1, &first); });
SSL_set_verify_nid_postfix(connection.Ssl(), 3, &first);
expected.ssl.verifyMode = 3;
expected.internal.verifyCallback = &first;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
SSL_set_verify_nid_postfix(connection.Ssl(), -1, nullptr);
expected.ssl.verifyMode = -1;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
SSL_set_verify_nid_postfix(connection.Ssl(), 1, &second);
expected.ssl.verifyMode = 1;
expected.internal.verifyCallback = &second;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
connection.ssl.internal = nullptr;
SSL_set_verify_nid_postfix(connection.Ssl(), 2, nullptr);
Require(connection.ssl.verifyMode == 2);
RequireThrows([&] { SSL_set_verify_nid_postfix(connection.Ssl(), 5, &first); });
Require(connection.ssl.verifyMode == 2);
}
static void TestGetAlpnSelected() {
static const unsigned char protocol[] = "h2";
TestSsl3Internal stateInternal {};
TestSsl3 state {};
Connection connection;
const Connection expected = connection;
const unsigned char* data = reinterpret_cast<const unsigned char*>(1);
unsigned int length = 77;
RequireThrows([&] { SSL_get0_alpn_selected_nid_postfix(nullptr, &data, &length); });
RequireThrows([&] { SSL_get0_alpn_selected_nid_postfix(connection.Ssl(), nullptr, &length); });
RequireThrows([&] { SSL_get0_alpn_selected_nid_postfix(connection.Ssl(), &data, nullptr); });
SSL_get0_alpn_selected_nid_postfix(connection.Ssl(), &data, &length);
Require(data == nullptr && length == 0);
connection.ssl.s3 = &state;
RequireThrows([&] { SSL_get0_alpn_selected_nid_postfix(connection.Ssl(), &data, &length); });
state.internal = &stateInternal;
Fill(stateInternal, 0x70);
stateInternal.alpnSelected = protocol;
stateInternal.alpnSelectedLength = 2;
data = nullptr;
SSL_get0_alpn_selected_nid_postfix(connection.Ssl(), &data, &length);
Require(data == protocol && length == 2);
stateInternal.alpnSelected = nullptr;
stateInternal.alpnSelectedLength = 0;
SSL_get0_alpn_selected_nid_postfix(connection.Ssl(), &data, &length);
Require(data == nullptr && length == 0);
connection.ssl.s3 = nullptr;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
}
static void TestSetConnectState() {
int accept = 0;
int connect = 0;
TestMethodInternal methodInternal {};
TestMethod method {};
Fill(methodInternal, 0x30);
methodInternal.accept = &accept;
methodInternal.connect = &connect;
method.internal = &methodInternal;
Connection connection;
connection.ssl.method = &method;
connection.ssl.server = 1;
connection.internal.shutdown = 3;
connection.internal.state = 0x1234;
Connection expected = connection;
RequireThrows([] { SSL_set_connect_state_nid_postfix(nullptr); });
SSL_set_connect_state_nid_postfix(connection.Ssl());
expected.ssl.server = 0;
expected.internal.shutdown = 0;
expected.internal.state = 0x5000;
expected.internal.handshakeFunc = &connect;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
methodInternal.connect = nullptr;
connection.internal.handshakeFunc = &accept;
SSL_set_connect_state_nid_postfix(connection.Ssl());
Require(connection.internal.handshakeFunc == nullptr);
connection.ssl.server = 1;
method.internal = nullptr;
RequireThrows([&] { SSL_set_connect_state_nid_postfix(connection.Ssl()); });
connection.ssl.method = nullptr;
RequireThrows([&] { SSL_set_connect_state_nid_postfix(connection.Ssl()); });
connection.ssl.method = &method;
method.internal = &methodInternal;
connection.ssl.internal = nullptr;
RequireThrows([&] { SSL_set_connect_state_nid_postfix(connection.Ssl()); });
Require(connection.ssl.server == 1);
}
static void TestControlReadAhead() {
Connection connection;
Connection expected = connection;
RequireThrows([] { SSL_ctrl_nid_postfix(nullptr, 40, 0, nullptr); });
connection.internal.readAhead = -1;
expected.internal.readAhead = -1;
Require(Control(connection, 40, 5) == -1);
Require(Control(connection, 41, INT64_C(0x123456789ABCDEF0)) == -1);
expected.internal.readAhead = static_cast<int>(0x9ABCDEF0u);
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
Require(Control(connection, 40, 0) == INT64_C(-1698898192));
Require(Control(connection, 41, 1) == INT64_C(-1698898192));
Require(Control(connection, 40, 0) == 1);
connection.ssl.internal = nullptr;
RequireThrows([&] { Control(connection, 40, 0); });
RequireThrows([&] { Control(connection, 41, 0); });
}
static void TestControlMessageCallbackArgument() {
int argument = 0;
Connection connection;
Connection expected = connection;
Require(Control(connection, 16, 9, &argument) == 1);
expected.internal.msgCallbackArg = &argument;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
Require(Control(connection, 16, 0, nullptr) == 1);
Require(connection.internal.msgCallbackArg == nullptr);
connection.ssl.internal = nullptr;
RequireThrows([&] { Control(connection, 16, 0, &argument); });
}
static void TestControlOptionsAndMode() {
Connection connection;
connection.internal.options = 0x4;
connection.internal.mode = 0;
Connection expected = connection;
Require(Control(connection, 32, 0x10) == 0x14);
Require(Control(connection, 32, INT64_C(0x100000000)) == INT64_C(0x100000014));
Require(Control(connection, 77, 0x4) == INT64_C(0x100000010));
Require(Control(connection, 32, 0) == INT64_C(0x100000010));
Require(Control(connection, 32, -1) == -1);
Require(Control(connection, 77, -1) == 0);
Require(Control(connection, 33, 0x2) == 0x2);
Require(Control(connection, 33, INT64_C(0x800000000)) == INT64_C(0x800000002));
Require(Control(connection, 78, 0x2) == INT64_C(0x800000000));
Require(Control(connection, 78, -1) == 0);
Require(Control(connection, 33, 0x5) == 0x5);
expected.internal.options = 0;
expected.internal.mode = 0x5;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
connection.ssl.internal = nullptr;
RequireThrows([&] { Control(connection, 32, 1); });
RequireThrows([&] { Control(connection, 77, 1); });
RequireThrows([&] { Control(connection, 33, 1); });
RequireThrows([&] { Control(connection, 78, 1); });
}
static void TestControlMaxCertList() {
Connection connection;
connection.internal.maxCertList = 102400;
Connection expected = connection;
Require(Control(connection, 50, 7) == 102400);
Require(Control(connection, 51, INT64_C(0x123456789)) == 102400);
Require(Control(connection, 50, 0) == INT64_C(0x123456789));
Require(Control(connection, 51, -5) == INT64_C(0x123456789));
expected.internal.maxCertList = -5;
Require(Same(connection.ssl, expected.ssl) && Same(connection.internal, expected.internal));
connection.ssl.internal = nullptr;
RequireThrows([&] { Control(connection, 50, 0); });
RequireThrows([&] { Control(connection, 51, 0); });
}
static void TestControlMtu() {
TestMethodInternal methodInternal {};
TestMethod method {};
TestDtls1Internal dtlsInternal {};
TestDtls1 dtls {};
Fill(dtlsInternal, 0x50);
method.internal = &methodInternal;
methodInternal.version = 0x0303;
Connection connection;
connection.ssl.internal = nullptr;
Connection expected = connection;
Require(Control(connection, 17, 227) == 0);
Require(Control(connection, 17, -1) == 0);
Require(Control(connection, 17, INT64_MIN) == 0);
Require(SSL_ctrl_nid_postfix(nullptr, 17, 227, nullptr) == 0);
Require(SSL_ctrl_nid_postfix(nullptr, 17, -1, nullptr) == 0);
RequireThrows([] { SSL_ctrl_nid_postfix(nullptr, 17, 228, nullptr); });
RequireThrows([&] { Control(connection, 17, 228); });
connection.ssl.method = &method;
expected.ssl.method = &method;
Require(Control(connection, 17, 228) == 0);
Require(Control(connection, 17, 1500) == 0);
Require(Same(connection.ssl, expected.ssl));
methodInternal.version = 0xFEFF;
RequireThrows([&] { Control(connection, 17, 1500); });
connection.ssl.d1 = &dtls;
RequireThrows([&] { Control(connection, 17, 1500); });
dtls.internal = &dtlsInternal;
TestDtls1Internal dtlsExpected = dtlsInternal;
Require(Control(connection, 17, 227) == 0);
Require(Same(dtlsInternal, dtlsExpected));
Require(Control(connection, 17, 228) == 228);
dtlsExpected.mtu = 228;
Require(Same(dtlsInternal, dtlsExpected));
Require(Control(connection, 17, INT64_C(0x100000500)) == INT64_C(0x100000500));
dtlsExpected.mtu = 0x500;
Require(Same(dtlsInternal, dtlsExpected));
method.internal = nullptr;
RequireThrows([&] { Control(connection, 17, 1500); });
}
static void TestControlMaxSendFragment() {
Connection connection;
connection.ssl.internal = nullptr;
connection.ssl.maxSendFragment = 16384;
Connection expected = connection;
for (std::int64_t argument : {INT64_C(511), INT64_C(16385), INT64_C(0), INT64_C(-1), INT64_C(0x100000200), INT64_C(1) << 60}) {
Require(Control(connection, 52, argument) == 0);
Require(Same(connection.ssl, expected.ssl));
}
Require(SSL_ctrl_nid_postfix(nullptr, 52, 511, nullptr) == 0);
Require(SSL_ctrl_nid_postfix(nullptr, 52, 16385, nullptr) == 0);
RequireThrows([] { SSL_ctrl_nid_postfix(nullptr, 52, 512, nullptr); });
Require(Control(connection, 52, 512) == 1);
expected.ssl.maxSendFragment = 512;
Require(Same(connection.ssl, expected.ssl));
Require(Control(connection, 52, 16384) == 1);
expected.ssl.maxSendFragment = 16384;
Require(Same(connection.ssl, expected.ssl));
Require(Control(connection, 52, 4096) == 1);
expected.ssl.maxSendFragment = 4096;
Require(Same(connection.ssl, expected.ssl));
}
static void TestControlRenegotiationInfoSupport() {
TestSsl3Internal stateInternal {};
TestSsl3 state {};
Connection connection;
connection.ssl.internal = nullptr;
Connection expected = connection;
RequireThrows([] { SSL_ctrl_nid_postfix(nullptr, 76, 0, nullptr); });
Require(Control(connection, 76, 1) == 0);
connection.ssl.s3 = &state;
RequireThrows([&] { Control(connection, 76, 0); });
state.internal = &stateInternal;
Fill(stateInternal, 0x60);
stateInternal.sendConnectionBinding = 1;
Require(Control(connection, 76, 0) == 1);
stateInternal.sendConnectionBinding = -1;
Require(Control(connection, 76, 0) == -1);
stateInternal.sendConnectionBinding = 0;
Require(Control(connection, 76, 0) == 0);
connection.ssl.s3 = nullptr;
Require(Same(connection.ssl, expected.ssl));
}
static void TestControlNullConnection() {
for (int command : {16, 32, 33, 50, 51, 77, 78}) RequireThrows([&] { SSL_ctrl_nid_postfix(nullptr, command, 1, nullptr); });
}
int main() {
TestSetVerify();
TestGetAlpnSelected();
TestSetConnectState();
TestControlReadAhead();
TestControlMessageCallbackArgument();
TestControlOptionsAndMode();
TestControlMaxCertList();
TestControlMtu();
TestControlMaxSendFragment();
TestControlRenegotiationInfoSupport();
TestControlNullConnection();
return 0;
}