mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
150 lines
8.5 KiB
C++
150 lines
8.5 KiB
C++
#include "prx/libSceLibreSsl/include/Api.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <exception>
|
|
#include <limits>
|
|
#include <string>
|
|
|
|
using StringFunction = const char* (APS5_VABI*)(std::int64_t);
|
|
|
|
void Check(StringFunction function, const char* name, std::int64_t value, const char* expected) {
|
|
const char* actual = function(value);
|
|
if (actual == nullptr || std::strcmp(actual, expected) != 0) {
|
|
std::fprintf(stderr, "%s(%lld): expected %s, got %s\n", name, static_cast<long long>(value), expected, actual ? actual : "(null)");
|
|
std::abort();
|
|
}
|
|
}
|
|
|
|
constexpr std::int32_t GeneralizedTime = 24;
|
|
constexpr std::uint64_t OcspError = 0x27fffull << 12;
|
|
constexpr std::uint64_t ErrorInNextUpdate = OcspError | 122;
|
|
constexpr std::uint64_t ErrorInThisUpdate = OcspError | 123;
|
|
constexpr std::uint64_t NextUpdateBeforeThisUpdate = OcspError | 124;
|
|
constexpr std::uint64_t StatusExpired = OcspError | 125;
|
|
constexpr std::uint64_t StatusNotYetValid = OcspError | 126;
|
|
constexpr std::uint64_t StatusTooOld = OcspError | 127;
|
|
constexpr std::int64_t Century = 3155760000;
|
|
|
|
struct TimeString {
|
|
std::string text;
|
|
Asn1String value;
|
|
|
|
explicit TimeString(const char* input, std::int32_t type = GeneralizedTime)
|
|
: text(input), value{static_cast<std::int32_t>(text.size()), type, reinterpret_cast<unsigned char*>(text.data()), 0} {}
|
|
TimeString(const TimeString&) = delete;
|
|
TimeString& operator=(const TimeString&) = delete;
|
|
};
|
|
|
|
void CheckValidity(const char* name, const Asn1String* thisUpdate, const Asn1String* nextUpdate, std::int64_t slack, std::int64_t maxAge, int expected, std::uint64_t error) {
|
|
ERR_clear_error_nid_postfix();
|
|
const int actual = OCSP_check_validity_nid_postfix(thisUpdate, nextUpdate, slack, maxAge);
|
|
const std::uint64_t first = ERR_get_error_nid_postfix();
|
|
const std::uint64_t second = ERR_get_error_nid_postfix();
|
|
if (actual != expected || first != error || second != 0) {
|
|
std::fprintf(stderr, "OCSP_check_validity %s: expected %d and 0x%llx, got %d, 0x%llx and 0x%llx\n", name, expected, static_cast<unsigned long long>(error), actual,
|
|
static_cast<unsigned long long>(first), static_cast<unsigned long long>(second));
|
|
std::abort();
|
|
}
|
|
}
|
|
|
|
void CheckValidity() {
|
|
constexpr auto Maximum = std::numeric_limits<std::int64_t>::max();
|
|
constexpr auto Minimum = std::numeric_limits<std::int64_t>::min();
|
|
const TimeString past("20000101000000Z");
|
|
const TimeString pastSecond("20000101000001Z");
|
|
const TimeString future("99991231235959Z");
|
|
const TimeString yearZero("00000101000000Z");
|
|
const TimeString february("20000231000000Z");
|
|
const TimeString march("20000301000000Z");
|
|
const TimeString utcType("20000101000000Z", 23);
|
|
const TimeString octetType("20000101000000Z", 4);
|
|
const TimeString untyped("99991231235959Z", 0);
|
|
|
|
CheckValidity("valid window", &past.value, &future.value, 0, -1, 1, 0);
|
|
CheckValidity("no next update", &past.value, nullptr, 0, -1, 1, 0);
|
|
CheckValidity("minimum age skips the age check", &past.value, &future.value, 0, Minimum, 1, 0);
|
|
CheckValidity("year zero", &yearZero.value, &future.value, 0, -1, 1, 0);
|
|
CheckValidity("UTCTime type", &utcType.value, &untyped.value, 0, -1, 1, 0);
|
|
CheckValidity("octet string type", &octetType.value, &untyped.value, 0, -1, 1, 0);
|
|
CheckValidity("not yet valid", &future.value, &future.value, 0, -1, 0, StatusNotYetValid);
|
|
CheckValidity("not yet valid before expired", &future.value, &past.value, 0, -1, 0, StatusNotYetValid);
|
|
CheckValidity("expired", &past.value, &past.value, 0, -1, 0, StatusExpired);
|
|
CheckValidity("too old", &past.value, &future.value, 0, 3600, 0, StatusTooOld);
|
|
CheckValidity("zero age", &past.value, &future.value, 0, 0, 0, StatusTooOld);
|
|
CheckValidity("next update before this update", &pastSecond.value, &past.value, Century, -1, 0, NextUpdateBeforeThisUpdate);
|
|
CheckValidity("next update equal to this update", &past.value, &past.value, Century, -1, 1, 0);
|
|
CheckValidity("expired before next update before this update", &pastSecond.value, &past.value, 0, -1, 0, StatusExpired);
|
|
CheckValidity("too old before expired", &past.value, &past.value, 0, 3600, 0, StatusTooOld);
|
|
CheckValidity("not yet valid before too old", &past.value, &future.value, -Century, 0, 0, StatusNotYetValid);
|
|
CheckValidity("February 31 before March 1", &february.value, &march.value, Century, -1, 1, 0);
|
|
CheckValidity("March 1 after February 31", &march.value, &february.value, Century, -1, 0, NextUpdateBeforeThisUpdate);
|
|
|
|
const char* invalid[] {"000101000000Z", "20000101000000.5Z", "2000010100000aZ", "200001010000000", "20000101000000z", "20001301000000Z", "20000001000000Z",
|
|
"20000100000000Z", "20000132000000Z", "20000101240000Z", "20000101006000Z", "20000101000060Z", " 0000101000000Z", "-0000101000000Z", "+0000101000000Z",
|
|
"\xb2" "0000101000000Z", "20000101000000Z0", ""};
|
|
for (const char* text : invalid) {
|
|
const TimeString time(text);
|
|
CheckValidity(text, &time.value, &future.value, 0, -1, 0, ErrorInThisUpdate);
|
|
CheckValidity(text, &past.value, &time.value, 0, -1, 0, ErrorInNextUpdate);
|
|
}
|
|
const TimeString month("20001301000000Z");
|
|
CheckValidity("invalid this update without next update", &month.value, nullptr, 0, -1, 0, ErrorInThisUpdate);
|
|
CheckValidity("not yet valid before invalid next update", &future.value, &month.value, 0, -1, 0, StatusNotYetValid);
|
|
const Asn1String missing{15, GeneralizedTime, nullptr, 0};
|
|
CheckValidity("null data", &missing, &future.value, 0, -1, 0, ErrorInThisUpdate);
|
|
CheckValidity("null next update data", &past.value, &missing, 0, -1, 0, ErrorInNextUpdate);
|
|
const Asn1String negative{-1, GeneralizedTime, past.value.data, 0};
|
|
CheckValidity("negative length", &negative, &future.value, 0, -1, 0, ErrorInThisUpdate);
|
|
|
|
CheckValidity("wrapping slack", &past.value, &future.value, Maximum, -1, 0, 0);
|
|
CheckValidity("wrapping slack without next update", &past.value, nullptr, Maximum, -1, 0, 0);
|
|
CheckValidity("wrapping negative slack", &past.value, &future.value, Minimum, -1, 0, 0);
|
|
CheckValidity("slack beyond the calendar", &past.value, &future.value, 70000000000000000, -1, 0, 0);
|
|
CheckValidity("negative slack beyond the calendar", &past.value, &future.value, -70000000000000000, -1, 0, 0);
|
|
CheckValidity("age beyond the calendar", &past.value, &future.value, 0, Maximum, 0, 0);
|
|
CheckValidity("slack inside the calendar", &past.value, &future.value, 60000000000000000, -1, 1, 0);
|
|
CheckValidity("age inside the calendar", &past.value, nullptr, 0, 60000000000000000, 1, 0);
|
|
|
|
try {
|
|
OCSP_check_validity_nid_postfix(nullptr, &future.value, 0, -1);
|
|
} catch (const std::exception&) {
|
|
return;
|
|
}
|
|
std::fprintf(stderr, "OCSP_check_validity: a null this update must throw\n");
|
|
std::abort();
|
|
}
|
|
|
|
int main() {
|
|
CheckValidity();
|
|
|
|
constexpr auto Unknown = "(UNKNOWN)";
|
|
constexpr std::int64_t Outside[] {-1, 4, 7, 9, 0x100, 0x100000000, std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::max()};
|
|
|
|
const char* responses[] {"successful", "malformedrequest", "internalerror", "trylater", nullptr, "sigrequired", "unauthorized"};
|
|
for (std::int64_t code = 0; code < 7; ++code) {
|
|
Check(OCSP_response_status_str_nid_postfix, "OCSP_response_status_str", code, responses[code] ? responses[code] : Unknown);
|
|
}
|
|
|
|
const char* certificates[] {"good", "revoked", "unknown"};
|
|
for (std::int64_t code = 0; code < 3; ++code) {
|
|
Check(OCSP_cert_status_str_nid_postfix, "OCSP_cert_status_str", code, certificates[code]);
|
|
}
|
|
|
|
const char* reasons[] {"unspecified", "keyCompromise", "cACompromise", "affiliationChanged", "superseded", "cessationOfOperation", "certificateHold", nullptr, "removeFromCRL"};
|
|
for (std::int64_t code = 0; code < 9; ++code) {
|
|
Check(OCSP_crl_reason_str_nid_postfix, "OCSP_crl_reason_str", code, reasons[code] ? reasons[code] : Unknown);
|
|
}
|
|
|
|
for (const auto value : Outside) {
|
|
Check(OCSP_response_status_str_nid_postfix, "OCSP_response_status_str", value, Unknown);
|
|
Check(OCSP_cert_status_str_nid_postfix, "OCSP_cert_status_str", value, Unknown);
|
|
if (value != 4) Check(OCSP_crl_reason_str_nid_postfix, "OCSP_crl_reason_str", value, Unknown);
|
|
}
|
|
Check(OCSP_response_status_str_nid_postfix, "OCSP_response_status_str", 0x100000000 | 1, Unknown);
|
|
Check(OCSP_crl_reason_str_nid_postfix, "OCSP_crl_reason_str", -0x100000000 | 8, Unknown);
|
|
return 0;
|
|
}
|