Make safe for editing certificate function

As long memory max bounds are still respected
This commit is contained in:
luigoalma 2021-05-06 18:46:48 +01:00 committed by d0k3
parent 4b5ac1a8e0
commit 41d36c620f
2 changed files with 48 additions and 2 deletions

View File

@ -298,6 +298,48 @@ u32 Certificate_VerifySignatureBlock(const Certificate* cert, const void* sig, u
return 1; return 1;
} }
static inline void* _Certificate_SafeRealloc(void* ptr, size_t size, size_t oldsize) {
void* new_ptr;
size_t min_size = min(oldsize, size);
if ((u32)ptr >= (u32)&_CommonCertsStorage && (u32)ptr < (u32)&_CommonCertsStorage + sizeof(_CommonCertsStorage)) {
new_ptr = malloc(size);
if (new_ptr) memcpy(new_ptr, ptr, min_size);
} else {
new_ptr = realloc(ptr, size);
}
if (!new_ptr) return NULL;
memset(&((u8*)new_ptr)[min_size], 0, size - min_size);
return new_ptr;
}
// will reallocate memory for certificate signature and body to fit the max possible size.
// will also allocate an empty object if Certificate is NULL initialized.
// if certificate points to static storage, an allocated version will be created.
// if function fails, the Certificate, even if previously NULL initialized, still has to be passed to cleaned up after use.
u32 Certificate_MakeEditSafe(Certificate* cert) {
if (!cert) return 1;
bool isvalid = Certificate_IsValid(cert);
if ((cert->sig || cert->data) && !isvalid) return 1;
Certificate cert_local;
u32 sig_size = isvalid ? _Certificate_GetSignatureChunkSizeFromType(getbe32(cert->sig->sig_type)) : 0;
u32 data_size = isvalid ? _Certificate_GetDataChunkSizeFromType(getbe32(cert->data->keytype)) : 0;
if (isvalid && (sig_size == 0 || data_size == 0)) return 1;
cert_local.sig = _Certificate_SafeRealloc(cert->sig, CERT_RSA4096_SIG_SIZE, sig_size);
if (!cert_local.sig) return 1;
cert->sig = cert_local.sig;
cert_local.data = _Certificate_SafeRealloc(cert->data, CERT_RSA4096_BODY_SIZE, data_size);
if (!cert_local.data) return 1;
cert->data = cert_local.data;
return 0;
}
static u32 _Certificate_AllocCopyOutImpl(const Certificate* cert, Certificate* out_cert) { static u32 _Certificate_AllocCopyOutImpl(const Certificate* cert, Certificate* out_cert) {
u32 sig_size = _Certificate_GetSignatureChunkSizeFromType(getbe32(cert->sig->sig_type)); u32 sig_size = _Certificate_GetSignatureChunkSizeFromType(getbe32(cert->sig->sig_type));
u32 data_size = _Certificate_GetDataChunkSizeFromType(getbe32(cert->data->keytype)); u32 data_size = _Certificate_GetDataChunkSizeFromType(getbe32(cert->data->keytype));
@ -598,6 +640,7 @@ static u32 _ProcessNextCertDbEntry(const char* path, DisaDiffRWInfo* info, Certi
return 0; return 0;
} }
// certificates returned by this call are not to be deemed safe to edit, pointers or pointed data
u32 LoadCertFromCertDb(Certificate* cert, const char* issuer) { u32 LoadCertFromCertDb(Certificate* cert, const char* issuer) {
if (!issuer || !cert) return 1; if (!issuer || !cert) return 1;
@ -609,7 +652,7 @@ u32 LoadCertFromCertDb(Certificate* cert, const char* issuer) {
int ret = 1; int ret = 1;
for (int i = 0; i < 2 && ret; ++i) { for (int i = 0; i < 2 && ret; ++i) {
Certificate cert_local = {NULL, NULL}; Certificate cert_local = CERTIFICATE_NULL_INIT;
char path[16]; char path[16];
DisaDiffRWInfo info; DisaDiffRWInfo info;
@ -686,7 +729,7 @@ u32 BuildRawCertBundleFromCertDb(void* rawout, size_t* size, const char* const*
int ret = 0; int ret = 0;
for (int i = 0; i < 2 && loaded_count != count && !ret; ++i) { for (int i = 0; i < 2 && loaded_count != count && !ret; ++i) {
Certificate cert_local = {NULL, NULL}; Certificate cert_local = CERTIFICATE_NULL_INIT;
char path[16]; char path[16];
DisaDiffRWInfo info; DisaDiffRWInfo info;

View File

@ -11,6 +11,8 @@
#define CERT_RSA2048_BODY_SIZE (sizeof(CertificateBody) + 0x138) #define CERT_RSA2048_BODY_SIZE (sizeof(CertificateBody) + 0x138)
#define CERT_ECC_BODY_SIZE (sizeof(CertificateBody) + 0x78) #define CERT_ECC_BODY_SIZE (sizeof(CertificateBody) + 0x78)
#define CERTIFICATE_NULL_INIT ((Certificate){NULL, NULL})
// from: http://3dbrew.org/wiki/Certificates // from: http://3dbrew.org/wiki/Certificates
// all numbers in big endian // all numbers in big endian
typedef struct { typedef struct {
@ -44,6 +46,7 @@ u32 Certificate_GetSignatureChunkSize(const Certificate* cert, u32* size);
u32 Certificate_GetDataChunkSize(const Certificate* cert, u32* size); u32 Certificate_GetDataChunkSize(const Certificate* cert, u32* size);
u32 Certificate_GetFullSize(const Certificate* cert, u32* size); u32 Certificate_GetFullSize(const Certificate* cert, u32* size);
u32 Certificate_VerifySignatureBlock(const Certificate* cert, const void* sig, u32 sig_size, const void* data, u32 data_size, bool sha256); u32 Certificate_VerifySignatureBlock(const Certificate* cert, const void* sig, u32 sig_size, const void* data, u32 data_size, bool sha256);
u32 Certificate_MakeEditSafe(Certificate* cert);
u32 Certificate_AllocCopyOut(const Certificate* cert, Certificate* out_cert); u32 Certificate_AllocCopyOut(const Certificate* cert, Certificate* out_cert);
u32 Certificate_RawCopy(const Certificate* cert, void* raw); u32 Certificate_RawCopy(const Certificate* cert, void* raw);
u32 Certificate_Cleanup(Certificate* cert); u32 Certificate_Cleanup(Certificate* cert);