mirror of
https://github.com/jakcron/nstool
synced 2024-11-15 02:06:40 +00:00
[nx|nstool] Replaced AciHeader,AciBinary,AcidBinary.
This commit is contained in:
parent
726c272f04
commit
b7207e8429
16 changed files with 726 additions and 885 deletions
53
lib/libnx/include/nx/AccessControlInfoBinary.h
Normal file
53
lib/libnx/include/nx/AccessControlInfoBinary.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/ISerialisable.h>
|
||||
#include <nx/aci.h>
|
||||
#include <nx/FacBinary.h>
|
||||
#include <nx/SacBinary.h>
|
||||
#include <nx/KcBinary.h>
|
||||
|
||||
namespace nx
|
||||
{
|
||||
class AccessControlInfoBinary : public fnd::ISerialisable
|
||||
{
|
||||
public:
|
||||
AccessControlInfoBinary();
|
||||
AccessControlInfoBinary(const AccessControlInfoBinary& other);
|
||||
|
||||
void operator=(const AccessControlInfoBinary& other);
|
||||
bool operator==(const AccessControlInfoBinary& other) const;
|
||||
bool operator!=(const AccessControlInfoBinary& other) const;
|
||||
|
||||
// export/import binary
|
||||
void toBytes();
|
||||
void fromBytes(const byte_t* data, size_t len);
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
// variables
|
||||
void clear();
|
||||
|
||||
uint64_t getProgramId() const;
|
||||
void setProgramId(uint64_t program_id);
|
||||
|
||||
const nx::FacBinary& getFileSystemAccessControl() const;
|
||||
void setFileSystemAccessControl(const FacBinary& fac);
|
||||
|
||||
const nx::SacBinary& getServiceAccessControl() const;
|
||||
void setServiceAccessControl(const SacBinary& sac);
|
||||
|
||||
const nx::KcBinary& getKernelCapabilities() const;
|
||||
void setKernelCapabilities(const KcBinary& kc);
|
||||
private:
|
||||
const std::string kModuleName = "ACCESS_CONTROL_INFO_BINARY";
|
||||
|
||||
// raw data
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// variables
|
||||
uint64_t mProgramId;
|
||||
nx::FacBinary mFileSystemAccessControl;
|
||||
nx::SacBinary mServiceAccessControl;
|
||||
nx::KcBinary mKernelCapabilities;
|
||||
};
|
||||
}
|
88
lib/libnx/include/nx/AccessControlInfoDescBinary.h
Normal file
88
lib/libnx/include/nx/AccessControlInfoDescBinary.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/List.h>
|
||||
#include <fnd/ISerialisable.h>
|
||||
#include <nx/aci.h>
|
||||
#include <nx/FacBinary.h>
|
||||
#include <nx/SacBinary.h>
|
||||
#include <nx/KcBinary.h>
|
||||
|
||||
namespace nx
|
||||
{
|
||||
class AccessControlInfoDescBinary : public fnd::ISerialisable
|
||||
{
|
||||
public:
|
||||
struct sProgramIdRestrict
|
||||
{
|
||||
uint64_t min;
|
||||
uint64_t max;
|
||||
|
||||
void operator=(const sProgramIdRestrict& other)
|
||||
{
|
||||
min = other.min;
|
||||
max = other.max;
|
||||
}
|
||||
|
||||
bool operator==(const sProgramIdRestrict& other) const
|
||||
{
|
||||
return (min == other.min) \
|
||||
&& (max == other.max);
|
||||
}
|
||||
|
||||
bool operator!=(const sProgramIdRestrict& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
AccessControlInfoDescBinary();
|
||||
AccessControlInfoDescBinary(const AccessControlInfoDescBinary& other);
|
||||
|
||||
void operator=(const AccessControlInfoDescBinary& other);
|
||||
bool operator==(const AccessControlInfoDescBinary& other) const;
|
||||
bool operator!=(const AccessControlInfoDescBinary& other) const;
|
||||
|
||||
// export/import binary
|
||||
void toBytes();
|
||||
void fromBytes(const byte_t* data, size_t len);
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
void generateSignature(const crypto::rsa::sRsa2048Key& key);
|
||||
void validateSignature(const crypto::rsa::sRsa2048Key& key) const;
|
||||
|
||||
// variables
|
||||
void clear();
|
||||
|
||||
const crypto::rsa::sRsa2048Key& getNcaHeaderSignature2Key() const;
|
||||
void setNcaHeaderSignature2Key(const crypto::rsa::sRsa2048Key& key);
|
||||
|
||||
const fnd::List<aci::Flag>& getFlagList() const;
|
||||
void setFlagList(const fnd::List<aci::Flag>& flags);
|
||||
|
||||
const sProgramIdRestrict& getProgramIdRestrict() const;
|
||||
void setProgramIdRestrict(const sProgramIdRestrict& pid_restrict);
|
||||
|
||||
const FacBinary& getFileSystemAccessControl() const;
|
||||
void setFileSystemAccessControl(const FacBinary& fac);
|
||||
|
||||
const SacBinary& getServiceAccessControl() const;
|
||||
void setServiceAccessControl(const SacBinary& sac);
|
||||
|
||||
const KcBinary& getKernelCapabilities() const;
|
||||
void setKernelCapabilities(const KcBinary& kc);
|
||||
private:
|
||||
const std::string kModuleName = "ACCESS_CONTROL_INFO_DESC_BINARY";
|
||||
|
||||
// raw data
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// variables
|
||||
crypto::rsa::sRsa2048Key mNcaHeaderSignature2Key;
|
||||
fnd::List<aci::Flag> mFlags;
|
||||
sProgramIdRestrict mProgramIdRestrict;
|
||||
nx::FacBinary mFileSystemAccessControl;
|
||||
nx::SacBinary mServiceAccessControl;
|
||||
nx::KcBinary mKernelCapabilities;
|
||||
};
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/List.h>
|
||||
#include <nx/AciHeader.h>
|
||||
#include <nx/FacBinary.h>
|
||||
#include <nx/SacBinary.h>
|
||||
#include <nx/KcBinary.h>
|
||||
|
||||
namespace nx
|
||||
{
|
||||
class AciBinary :
|
||||
public AciHeader
|
||||
{
|
||||
public:
|
||||
AciBinary();
|
||||
AciBinary(const AciBinary& other);
|
||||
|
||||
void operator=(const AciBinary& other);
|
||||
bool operator==(const AciBinary& other) const;
|
||||
bool operator!=(const AciBinary& other) const;
|
||||
|
||||
// export/import binary
|
||||
virtual void toBytes();
|
||||
virtual void fromBytes(const byte_t* bytes, size_t len);
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
// variables
|
||||
virtual void clear();
|
||||
|
||||
const FacBinary& getFac() const;
|
||||
void setFac(const FacBinary& fac);
|
||||
|
||||
const SacBinary& getSac() const;
|
||||
void setSac(const SacBinary& sac);
|
||||
|
||||
const KcBinary& getKc() const;
|
||||
void setKc(const KcBinary& kc);
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "ACI_BINARY";
|
||||
|
||||
// raw binary
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// variables
|
||||
FacBinary mFac;
|
||||
SacBinary mSac;
|
||||
KcBinary mKc;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/ISerialisable.h>
|
||||
#include <nx/aci.h>
|
||||
|
||||
namespace nx
|
||||
{
|
||||
class AciHeader :
|
||||
public fnd::ISerialisable
|
||||
{
|
||||
public:
|
||||
enum AciType
|
||||
{
|
||||
TYPE_ACI0, // for Access Control Info
|
||||
TYPE_ACID // for Access Control Info Desc
|
||||
};
|
||||
|
||||
struct sSection
|
||||
{
|
||||
size_t offset;
|
||||
size_t size;
|
||||
|
||||
void operator=(const sSection& other)
|
||||
{
|
||||
offset = other.offset;
|
||||
size = other.size;
|
||||
}
|
||||
|
||||
bool operator==(const sSection& other) const
|
||||
{
|
||||
return (offset == other.offset) \
|
||||
&& (size == other.size);
|
||||
}
|
||||
|
||||
bool operator!=(const sSection& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
};
|
||||
|
||||
AciHeader();
|
||||
AciHeader(const AciHeader& other);
|
||||
|
||||
void operator=(const AciHeader& other);
|
||||
bool operator==(const AciHeader& other) const;
|
||||
bool operator!=(const AciHeader& other) const;
|
||||
|
||||
// export/import binary
|
||||
virtual void toBytes();
|
||||
virtual void fromBytes(const byte_t* bytes, size_t len);
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
// variables
|
||||
virtual void clear();
|
||||
size_t getAciSize() const;
|
||||
|
||||
// ACI0 only
|
||||
uint64_t getProgramId() const;
|
||||
void setProgramId(uint64_t program_id);
|
||||
|
||||
// ACID only
|
||||
size_t getAcidSize() const;
|
||||
//void setAcidSize(size_t size);
|
||||
uint64_t getProgramIdMin() const;
|
||||
void setProgramIdMin(uint64_t program_id);
|
||||
uint64_t getProgramIdMax() const;
|
||||
void setProgramIdMax(uint64_t program_id);
|
||||
|
||||
// ACID & ACI0
|
||||
void setHeaderOffset(size_t offset);
|
||||
AciType getAciType() const;
|
||||
void setAciType(AciType type);
|
||||
bool isProduction() const;
|
||||
void setIsProduction(bool isProduction);
|
||||
bool isUnqualifiedApproval() const;
|
||||
void setIsUnqualifiedApproval(bool isUnqualifiedApproval);
|
||||
const sSection& getFacPos() const;
|
||||
void setFacSize(size_t size);
|
||||
const sSection& getSacPos() const;
|
||||
void setSacSize(size_t size);
|
||||
const sSection& getKcPos() const;
|
||||
void setKcSize(size_t size);
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "ACI_HEADER";
|
||||
|
||||
// raw data
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// ACI variables
|
||||
uint64_t mProgramId;
|
||||
|
||||
// ACID variables
|
||||
size_t mAcidSize;
|
||||
uint64_t mProgramIdMin;
|
||||
uint64_t mProgramIdMax;
|
||||
|
||||
// ACI(D) variables
|
||||
size_t mHeaderOffset;
|
||||
AciType mType;
|
||||
bool mIsProduction;
|
||||
bool mIsUnqualifiedApproval;
|
||||
sSection mFac, mSac, mKc;
|
||||
|
||||
void calculateSectionOffsets();
|
||||
};
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <nx/AciBinary.h>
|
||||
#include <crypto/rsa.h>
|
||||
|
||||
namespace nx
|
||||
{
|
||||
class AcidBinary :
|
||||
public AciBinary
|
||||
{
|
||||
public:
|
||||
AcidBinary();
|
||||
AcidBinary(const AcidBinary& other);
|
||||
|
||||
void operator=(const AcidBinary& other);
|
||||
bool operator==(const AcidBinary& other) const;
|
||||
bool operator!=(const AcidBinary& other) const;
|
||||
|
||||
// export/import binary
|
||||
void toBytes();
|
||||
void signBinary(const crypto::rsa::sRsa2048Key& key);
|
||||
void fromBytes(const byte_t* bytes, size_t len);
|
||||
void verifyBinary(const crypto::rsa::sRsa2048Key& key) const;
|
||||
const fnd::Vec<byte_t>& getBytes() const;
|
||||
|
||||
// variables
|
||||
virtual void clear();
|
||||
|
||||
const crypto::rsa::sRsa2048Key& getNcaHeader2RsaKey() const;
|
||||
void setNcaHeader2RsaKey(const crypto::rsa::sRsa2048Key& key);
|
||||
|
||||
private:
|
||||
const std::string kModuleName = "ACID_BINARY";
|
||||
|
||||
// raw binary
|
||||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// variables
|
||||
crypto::rsa::sRsa2048Key mEmbeddedPublicKey;
|
||||
};
|
||||
}
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
#include <string>
|
||||
#include <fnd/List.h>
|
||||
#include <nx/NpdmHeader.h>
|
||||
#include <nx/AciBinary.h>
|
||||
#include <nx/AcidBinary.h>
|
||||
#include <nx/AccessControlInfoBinary.h>
|
||||
#include <nx/AccessControlInfoDescBinary.h>
|
||||
|
||||
|
||||
namespace nx
|
||||
|
@ -27,11 +27,11 @@ namespace nx
|
|||
// variables
|
||||
void clear();
|
||||
|
||||
const AciBinary& getAci() const;
|
||||
void setAci(const AciBinary& aci);
|
||||
const AccessControlInfoBinary& getAci() const;
|
||||
void setAci(const AccessControlInfoBinary& aci);
|
||||
|
||||
const AcidBinary& getAcid() const;
|
||||
void setAcid(const AcidBinary& acid);
|
||||
const AccessControlInfoDescBinary& getAcid() const;
|
||||
void setAcid(const AccessControlInfoDescBinary& acid);
|
||||
private:
|
||||
const std::string kModuleName = "NPDM_BINARY";
|
||||
|
||||
|
@ -39,8 +39,8 @@ namespace nx
|
|||
fnd::Vec<byte_t> mRawBinary;
|
||||
|
||||
// variables
|
||||
AciBinary mAci;
|
||||
AcidBinary mAcid;
|
||||
AccessControlInfoBinary mAci;
|
||||
AccessControlInfoDescBinary mAcid;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
#include <crypto/rsa.h>
|
||||
#include <nx/macro.h>
|
||||
|
||||
namespace nx
|
||||
|
@ -8,35 +9,45 @@ namespace nx
|
|||
{
|
||||
static const uint32_t kAciStructMagic = _MAKE_STRUCT_MAGIC("ACI0");
|
||||
static const uint32_t kAciDescStructMagic = _MAKE_STRUCT_MAGIC("ACID");
|
||||
static const size_t kAciAlignSize = 0x10;
|
||||
static const size_t kSectionAlignSize = 0x10;
|
||||
|
||||
enum Flags
|
||||
enum Flag
|
||||
{
|
||||
FLAG_PRODUCTION,
|
||||
FLAG_UNQUALIFIED_APPROVAL
|
||||
};
|
||||
}
|
||||
#pragma pack(push,1)
|
||||
struct sAciSection
|
||||
{
|
||||
le_uint32_t offset;
|
||||
le_uint32_t size;
|
||||
};
|
||||
|
||||
struct sAciHeader
|
||||
{
|
||||
le_uint32_t st_magic;
|
||||
le_uint32_t size; // includes prefacing signature, set only in ACID made by SDK (it enables easy resigning)
|
||||
byte_t reserved_0[4];
|
||||
le_uint32_t flags; // set in ACID only
|
||||
union uProgramIdInfo
|
||||
{
|
||||
struct sRestrictProgramId
|
||||
{
|
||||
le_uint64_t min;
|
||||
le_uint64_t max;
|
||||
} program_id_restrict;
|
||||
byte_t reserved_00[0xC];
|
||||
le_uint64_t program_id;
|
||||
} program_id_info;
|
||||
struct sAciSection
|
||||
byte_t reserved_01[0x8];
|
||||
sAciSection fac;
|
||||
sAciSection sac;
|
||||
sAciSection kc;
|
||||
};
|
||||
|
||||
struct sAciDescHeader
|
||||
{
|
||||
le_uint32_t offset; // aligned by 0x10 from the last one
|
||||
le_uint32_t size;
|
||||
} fac, sac, kc;
|
||||
byte_t signature[crypto::rsa::kRsa2048Size];
|
||||
byte_t nca_rsa_signature2_modulus[crypto::rsa::kRsa2048Size];
|
||||
le_uint32_t st_magic;
|
||||
le_uint32_t signed_size;
|
||||
byte_t reserved_00[0x4];
|
||||
le_uint32_t flags;
|
||||
le_uint64_t program_id_min;
|
||||
le_uint64_t program_id_max;
|
||||
sAciSection fac;
|
||||
sAciSection sac;
|
||||
sAciSection kc;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
172
lib/libnx/source/AccessControlInfoBinary.cpp
Normal file
172
lib/libnx/source/AccessControlInfoBinary.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
#include <nx/AccessControlInfoBinary.h>
|
||||
|
||||
nx::AccessControlInfoBinary::AccessControlInfoBinary()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
nx::AccessControlInfoBinary::AccessControlInfoBinary(const AccessControlInfoBinary & other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::operator=(const AccessControlInfoBinary & other)
|
||||
{
|
||||
mRawBinary = other.mRawBinary;
|
||||
mProgramId = other.mProgramId;
|
||||
mFileSystemAccessControl = other.mFileSystemAccessControl;
|
||||
mServiceAccessControl = other.mServiceAccessControl;
|
||||
mKernelCapabilities = other.mKernelCapabilities;
|
||||
}
|
||||
|
||||
bool nx::AccessControlInfoBinary::operator==(const AccessControlInfoBinary & other) const
|
||||
{
|
||||
return (mProgramId == other.mProgramId) \
|
||||
&& (mFileSystemAccessControl == other.mFileSystemAccessControl) \
|
||||
&& (mServiceAccessControl == other.mServiceAccessControl) \
|
||||
&& (mKernelCapabilities == other.mKernelCapabilities);
|
||||
}
|
||||
|
||||
bool nx::AccessControlInfoBinary::operator!=(const AccessControlInfoBinary & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::toBytes()
|
||||
{
|
||||
if (mFileSystemAccessControl.getBytes().size() == 0)
|
||||
mFileSystemAccessControl.toBytes();
|
||||
|
||||
if (mServiceAccessControl.getBytes().size() == 0)
|
||||
mServiceAccessControl.toBytes();
|
||||
|
||||
if (mKernelCapabilities.getBytes().size() == 0)
|
||||
mKernelCapabilities.toBytes();
|
||||
|
||||
// determine section layout
|
||||
struct sLayout {
|
||||
uint32_t offset, size;
|
||||
} fac, sac, kc;
|
||||
|
||||
fac.offset = align(sizeof(sAciHeader), aci::kSectionAlignSize);
|
||||
fac.size = (uint32_t)mFileSystemAccessControl.getBytes().size();
|
||||
sac.offset = align(fac.offset + fac.size, aci::kSectionAlignSize);
|
||||
sac.size = (uint32_t)mServiceAccessControl.getBytes().size();
|
||||
kc.offset = align(sac.offset + sac.size, aci::kSectionAlignSize);
|
||||
kc.size = (uint32_t)mKernelCapabilities.getBytes().size();
|
||||
|
||||
// get total size
|
||||
size_t total_size = _MAX(_MAX(fac.offset + fac.size, sac.offset + sac.size), kc.offset + kc.size);
|
||||
|
||||
mRawBinary.alloc(total_size);
|
||||
sAciHeader* hdr = (sAciHeader*)mRawBinary.data();
|
||||
|
||||
// set type
|
||||
hdr->st_magic = aci::kAciStructMagic;
|
||||
|
||||
// set program id
|
||||
hdr->program_id = mProgramId;
|
||||
|
||||
// set offset/size
|
||||
hdr->fac.offset = fac.offset;
|
||||
hdr->fac.size = fac.size;
|
||||
hdr->sac.offset = sac.offset;
|
||||
hdr->sac.size = sac.size;
|
||||
hdr->kc.offset = kc.offset;
|
||||
hdr->kc.size = kc.size;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::fromBytes(const byte_t* data, size_t len)
|
||||
{
|
||||
// check size
|
||||
if (len < sizeof(sAciHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "AccessControlInfo binary is too small");
|
||||
}
|
||||
|
||||
// clear variables
|
||||
clear();
|
||||
|
||||
// save a copy of the header
|
||||
sAciHeader hdr;
|
||||
memcpy((void*)&hdr, data, sizeof(sAciHeader));
|
||||
|
||||
// check magic
|
||||
if (hdr.st_magic.get() != aci::kAciStructMagic)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "AccessControlInfo header corrupt");
|
||||
}
|
||||
|
||||
// get total size
|
||||
size_t total_size = _MAX(_MAX(hdr.fac.offset.get() + hdr.fac.size.get(), hdr.sac.offset.get() + hdr.sac.size.get()), hdr.kc.offset.get() + hdr.kc.size.get());
|
||||
|
||||
// validate binary size
|
||||
if (len < total_size)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "AccessControlInfo binary is too small");
|
||||
}
|
||||
|
||||
// allocate memory for header
|
||||
mRawBinary.alloc(total_size);
|
||||
memcpy(mRawBinary.data(), data, mRawBinary.size());
|
||||
|
||||
// save variables
|
||||
mProgramId = hdr.program_id.get();
|
||||
mFileSystemAccessControl.fromBytes(mRawBinary.data() + hdr.fac.offset.get(), hdr.fac.size.get());
|
||||
mServiceAccessControl.fromBytes(mRawBinary.data() + hdr.sac.offset.get(), hdr.sac.size.get());
|
||||
mKernelCapabilities.fromBytes(mRawBinary.data() + hdr.kc.offset.get(), hdr.kc.size.get());
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nx::AccessControlInfoBinary::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::clear()
|
||||
{
|
||||
mRawBinary.clear();
|
||||
mProgramId = 0;
|
||||
mFileSystemAccessControl.clear();
|
||||
mServiceAccessControl.clear();
|
||||
mKernelCapabilities.clear();
|
||||
}
|
||||
|
||||
uint64_t nx::AccessControlInfoBinary::getProgramId() const
|
||||
{
|
||||
return mProgramId;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::setProgramId(uint64_t program_id)
|
||||
{
|
||||
mProgramId = program_id;
|
||||
}
|
||||
|
||||
const nx::FacBinary& nx::AccessControlInfoBinary::getFileSystemAccessControl() const
|
||||
{
|
||||
return mFileSystemAccessControl;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::setFileSystemAccessControl(const nx::FacBinary& fac)
|
||||
{
|
||||
mFileSystemAccessControl = fac;
|
||||
}
|
||||
|
||||
const nx::SacBinary& nx::AccessControlInfoBinary::getServiceAccessControl() const
|
||||
{
|
||||
return mServiceAccessControl;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::setServiceAccessControl(const nx::SacBinary& sac)
|
||||
{
|
||||
mServiceAccessControl = sac;
|
||||
}
|
||||
|
||||
const nx::KcBinary& nx::AccessControlInfoBinary::getKernelCapabilities() const
|
||||
{
|
||||
return mKernelCapabilities;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoBinary::setKernelCapabilities(const nx::KcBinary& kc)
|
||||
{
|
||||
mKernelCapabilities = kc;
|
||||
}
|
250
lib/libnx/source/AccessControlInfoDescBinary.cpp
Normal file
250
lib/libnx/source/AccessControlInfoDescBinary.cpp
Normal file
|
@ -0,0 +1,250 @@
|
|||
#include <nx/AccessControlInfoDescBinary.h>
|
||||
|
||||
nx::AccessControlInfoDescBinary::AccessControlInfoDescBinary()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
nx::AccessControlInfoDescBinary::AccessControlInfoDescBinary(const AccessControlInfoDescBinary & other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::operator=(const AccessControlInfoDescBinary & other)
|
||||
{
|
||||
mRawBinary = other.mRawBinary;
|
||||
mNcaHeaderSignature2Key = other.mNcaHeaderSignature2Key;
|
||||
mFlags = other.mFlags;
|
||||
mProgramIdRestrict = other.mProgramIdRestrict;
|
||||
mFileSystemAccessControl = other.mFileSystemAccessControl;
|
||||
mServiceAccessControl = other.mServiceAccessControl;
|
||||
mKernelCapabilities = other.mKernelCapabilities;
|
||||
}
|
||||
|
||||
bool nx::AccessControlInfoDescBinary::operator==(const AccessControlInfoDescBinary & other) const
|
||||
{
|
||||
return (mNcaHeaderSignature2Key == other.mNcaHeaderSignature2Key) \
|
||||
&& (mFlags == other.mFlags) \
|
||||
&& (mProgramIdRestrict == other.mProgramIdRestrict) \
|
||||
&& (mFileSystemAccessControl == other.mFileSystemAccessControl) \
|
||||
&& (mServiceAccessControl == other.mServiceAccessControl) \
|
||||
&& (mKernelCapabilities == other.mKernelCapabilities);
|
||||
}
|
||||
|
||||
bool nx::AccessControlInfoDescBinary::operator!=(const AccessControlInfoDescBinary & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::toBytes()
|
||||
{
|
||||
if (mFileSystemAccessControl.getBytes().size() == 0)
|
||||
mFileSystemAccessControl.toBytes();
|
||||
|
||||
if (mServiceAccessControl.getBytes().size() == 0)
|
||||
mServiceAccessControl.toBytes();
|
||||
|
||||
if (mKernelCapabilities.getBytes().size() == 0)
|
||||
mKernelCapabilities.toBytes();
|
||||
|
||||
// determine section layout
|
||||
struct sLayout {
|
||||
uint32_t offset, size;
|
||||
} fac, sac, kc;
|
||||
|
||||
fac.offset = align(sizeof(sAciDescHeader), aci::kSectionAlignSize);
|
||||
fac.size = (uint32_t)mFileSystemAccessControl.getBytes().size();
|
||||
sac.offset = align(fac.offset + fac.size, aci::kSectionAlignSize);
|
||||
sac.size = (uint32_t)mServiceAccessControl.getBytes().size();
|
||||
kc.offset = align(sac.offset + sac.size, aci::kSectionAlignSize);
|
||||
kc.size = (uint32_t)mKernelCapabilities.getBytes().size();
|
||||
|
||||
// get total size
|
||||
size_t total_size = _MAX(_MAX(fac.offset + fac.size, sac.offset + sac.size), kc.offset + kc.size);
|
||||
|
||||
mRawBinary.alloc(total_size);
|
||||
sAciDescHeader* hdr = (sAciDescHeader*)mRawBinary.data();
|
||||
|
||||
// set rsa modulus
|
||||
memcpy(hdr->nca_rsa_signature2_modulus, mNcaHeaderSignature2Key.modulus, crypto::rsa::kRsa2048Size);
|
||||
|
||||
// set type
|
||||
hdr->st_magic = aci::kAciDescStructMagic;
|
||||
|
||||
// set "acid size"
|
||||
hdr->signed_size = total_size - crypto::rsa::kRsa2048Size;
|
||||
|
||||
// set flags
|
||||
uint32_t flags = 0;
|
||||
for (size_t i = 0; i < mFlags.size(); i++)
|
||||
flags |= _BIT(mFlags[i]);
|
||||
hdr->flags = flags;
|
||||
|
||||
// set program id restrict settings
|
||||
hdr->program_id_min = mProgramIdRestrict.min;
|
||||
hdr->program_id_max = mProgramIdRestrict.max;
|
||||
|
||||
// set offset/size
|
||||
hdr->fac.offset = fac.offset;
|
||||
hdr->fac.size = fac.size;
|
||||
hdr->sac.offset = sac.offset;
|
||||
hdr->sac.size = sac.size;
|
||||
hdr->kc.offset = kc.offset;
|
||||
hdr->kc.size = kc.size;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::fromBytes(const byte_t* data, size_t len)
|
||||
{
|
||||
// check size
|
||||
if (len < sizeof(sAciDescHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "AccessControlInfoDesc binary is too small");
|
||||
}
|
||||
|
||||
// clear variables
|
||||
clear();
|
||||
|
||||
// save a copy of the header
|
||||
sAciDescHeader hdr;
|
||||
memcpy((void*)&hdr, data, sizeof(sAciDescHeader));
|
||||
|
||||
// check magic
|
||||
if (hdr.st_magic.get() != aci::kAciDescStructMagic)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "AccessControlInfoDesc header corrupt");
|
||||
}
|
||||
|
||||
// get total size
|
||||
size_t total_size = _MAX(_MAX(hdr.fac.offset.get() + hdr.fac.size.get(), hdr.sac.offset.get() + hdr.sac.size.get()), hdr.kc.offset.get() + hdr.kc.size.get());
|
||||
|
||||
// validate binary size
|
||||
if (len < total_size)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "AccessControlInfoDesc binary is too small");
|
||||
}
|
||||
|
||||
// allocate memory for header
|
||||
mRawBinary.alloc(total_size);
|
||||
memcpy(mRawBinary.data(), data, mRawBinary.size());
|
||||
|
||||
// save variables
|
||||
memcpy(mNcaHeaderSignature2Key.modulus, hdr.nca_rsa_signature2_modulus, crypto::rsa::kRsa2048Size);
|
||||
|
||||
for (size_t i = 0; i < 32; i++)
|
||||
{
|
||||
if (_HAS_BIT(hdr.flags.get(), i))
|
||||
mFlags.addElement((aci::Flag)i);
|
||||
}
|
||||
|
||||
mProgramIdRestrict.min = hdr.program_id_min.get();
|
||||
mProgramIdRestrict.max = hdr.program_id_max.get();
|
||||
|
||||
mFileSystemAccessControl.fromBytes(mRawBinary.data() + hdr.fac.offset.get(), hdr.fac.size.get());
|
||||
mServiceAccessControl.fromBytes(mRawBinary.data() + hdr.sac.offset.get(), hdr.sac.size.get());
|
||||
mKernelCapabilities.fromBytes(mRawBinary.data() + hdr.kc.offset.get(), hdr.kc.size.get());
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nx::AccessControlInfoDescBinary::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::generateSignature(const crypto::rsa::sRsa2048Key& key)
|
||||
{
|
||||
if (mRawBinary.size() == 0)
|
||||
toBytes();
|
||||
|
||||
byte_t hash[crypto::sha::kSha256HashLen];
|
||||
crypto::sha::Sha256(mRawBinary.data() + crypto::rsa::kRsa2048Size, mRawBinary.size() - crypto::rsa::kRsa2048Size, hash);
|
||||
|
||||
if (crypto::rsa::pkcs::rsaSign(key, crypto::sha::HASH_SHA256, hash, mRawBinary.data()) != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Failed to sign Access Control Info Desc");
|
||||
}
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::validateSignature(const crypto::rsa::sRsa2048Key& key) const
|
||||
{
|
||||
if (mRawBinary.size() == 0)
|
||||
throw fnd::Exception(kModuleName, "No Access Control Info Desc binary exists to verify");
|
||||
|
||||
byte_t hash[crypto::sha::kSha256HashLen];
|
||||
crypto::sha::Sha256(mRawBinary.data() + crypto::rsa::kRsa2048Size, mRawBinary.size() - crypto::rsa::kRsa2048Size, hash);
|
||||
|
||||
if (crypto::rsa::pss::rsaVerify(key, crypto::sha::HASH_SHA256, hash, mRawBinary.data()) != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Failed to verify Access Control Info Desc");
|
||||
}
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::clear()
|
||||
{
|
||||
mRawBinary.clear();
|
||||
memset((void*)&mNcaHeaderSignature2Key, 0, sizeof(mNcaHeaderSignature2Key));
|
||||
mFlags.clear();
|
||||
mProgramIdRestrict.min = 0;
|
||||
mProgramIdRestrict.max = 0;
|
||||
mFileSystemAccessControl.clear();
|
||||
mServiceAccessControl.clear();
|
||||
mKernelCapabilities.clear();
|
||||
}
|
||||
|
||||
const crypto::rsa::sRsa2048Key& nx::AccessControlInfoDescBinary::getNcaHeaderSignature2Key() const
|
||||
{
|
||||
return mNcaHeaderSignature2Key;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::setNcaHeaderSignature2Key(const crypto::rsa::sRsa2048Key& key)
|
||||
{
|
||||
mNcaHeaderSignature2Key = key;
|
||||
}
|
||||
|
||||
const fnd::List<nx::aci::Flag>& nx::AccessControlInfoDescBinary::getFlagList() const
|
||||
{
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::setFlagList(const fnd::List<nx::aci::Flag>& flags)
|
||||
{
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
const nx::AccessControlInfoDescBinary::sProgramIdRestrict& nx::AccessControlInfoDescBinary::getProgramIdRestrict() const
|
||||
{
|
||||
return mProgramIdRestrict;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::setProgramIdRestrict(const sProgramIdRestrict& pid_restrict)
|
||||
{
|
||||
mProgramIdRestrict = pid_restrict;
|
||||
}
|
||||
|
||||
const nx::FacBinary& nx::AccessControlInfoDescBinary::getFileSystemAccessControl() const
|
||||
{
|
||||
return mFileSystemAccessControl;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::setFileSystemAccessControl(const nx::FacBinary& fac)
|
||||
{
|
||||
mFileSystemAccessControl = fac;
|
||||
}
|
||||
|
||||
const nx::SacBinary& nx::AccessControlInfoDescBinary::getServiceAccessControl() const
|
||||
{
|
||||
return mServiceAccessControl;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::setServiceAccessControl(const nx::SacBinary& sac)
|
||||
{
|
||||
mServiceAccessControl = sac;
|
||||
}
|
||||
|
||||
const nx::KcBinary& nx::AccessControlInfoDescBinary::getKernelCapabilities() const
|
||||
{
|
||||
return mKernelCapabilities;
|
||||
}
|
||||
|
||||
void nx::AccessControlInfoDescBinary::setKernelCapabilities(const nx::KcBinary& kc)
|
||||
{
|
||||
mKernelCapabilities = kc;
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
#include <nx/AciBinary.h>
|
||||
|
||||
nx::AciBinary::AciBinary()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
nx::AciBinary::AciBinary(const AciBinary & other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void nx::AciBinary::operator=(const AciBinary & other)
|
||||
{
|
||||
if (other.getBytes().size())
|
||||
{
|
||||
fromBytes(other.getBytes().data(), other.getBytes().size());
|
||||
}
|
||||
else
|
||||
{
|
||||
AciHeader::operator=(other);
|
||||
mFac = other.mFac;
|
||||
mSac = other.mSac;
|
||||
mKc = other.mKc;
|
||||
}
|
||||
}
|
||||
|
||||
bool nx::AciBinary::operator==(const AciBinary & other) const
|
||||
{
|
||||
return (AciHeader::operator==(other)) \
|
||||
&& (mFac == other.mFac) \
|
||||
&& (mSac == other.mSac) \
|
||||
&& (mKc == other.mKc);
|
||||
}
|
||||
|
||||
bool nx::AciBinary::operator!=(const AciBinary & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nx::AciBinary::toBytes()
|
||||
{
|
||||
// export components
|
||||
mFac.toBytes();
|
||||
mSac.toBytes();
|
||||
mKc.toBytes();
|
||||
|
||||
// set sizes
|
||||
setFacSize(mFac.getBytes().size());
|
||||
setSacSize(mSac.getBytes().size());
|
||||
setKcSize(mKc.getBytes().size());
|
||||
|
||||
// export header
|
||||
AciHeader::toBytes();
|
||||
|
||||
// allocate binary
|
||||
mRawBinary.alloc(getAciSize());
|
||||
|
||||
// copy header
|
||||
memcpy(mRawBinary.data(), AciHeader::getBytes().data(), AciHeader::getBytes().size());
|
||||
|
||||
// copy components
|
||||
memcpy(mRawBinary.data() + getFacPos().offset, mFac.getBytes().data(), mFac.getBytes().size());
|
||||
memcpy(mRawBinary.data() + getSacPos().offset, mSac.getBytes().data(), mSac.getBytes().size());
|
||||
memcpy(mRawBinary.data() + getKcPos().offset, mKc.getBytes().data(), mKc.getBytes().size());
|
||||
}
|
||||
|
||||
void nx::AciBinary::fromBytes(const byte_t * bytes, size_t len)
|
||||
{
|
||||
clear();
|
||||
|
||||
AciHeader::fromBytes(bytes, len);
|
||||
|
||||
if (getAciSize() > len)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "ACI binary too small");
|
||||
}
|
||||
|
||||
mRawBinary.alloc(getAciSize());
|
||||
memcpy(mRawBinary.data(), bytes, mRawBinary.size());
|
||||
|
||||
if (getFacPos().size > 0)
|
||||
{
|
||||
mFac.fromBytes(mRawBinary.data() + getFacPos().offset, getFacPos().size);
|
||||
}
|
||||
if (getSacPos().size > 0)
|
||||
{
|
||||
mSac.fromBytes(mRawBinary.data() + getSacPos().offset, getSacPos().size);
|
||||
}
|
||||
if (getKcPos().size > 0)
|
||||
{
|
||||
mKc.fromBytes(mRawBinary.data() + getKcPos().offset, getKcPos().size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nx::AciBinary::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
void nx::AciBinary::clear()
|
||||
{
|
||||
AciHeader::clear();
|
||||
mRawBinary.clear();
|
||||
mFac.clear();
|
||||
mSac.clear();
|
||||
mKc.clear();
|
||||
}
|
||||
|
||||
const nx::FacBinary & nx::AciBinary::getFac() const
|
||||
{
|
||||
return mFac;
|
||||
}
|
||||
|
||||
void nx::AciBinary::setFac(const FacBinary & fac)
|
||||
{
|
||||
mFac = fac;
|
||||
}
|
||||
|
||||
const nx::SacBinary & nx::AciBinary::getSac() const
|
||||
{
|
||||
return mSac;
|
||||
}
|
||||
|
||||
void nx::AciBinary::setSac(const SacBinary & sac)
|
||||
{
|
||||
mSac = sac;
|
||||
}
|
||||
|
||||
const nx::KcBinary & nx::AciBinary::getKc() const
|
||||
{
|
||||
return mKc;
|
||||
}
|
||||
|
||||
void nx::AciBinary::setKc(const KcBinary & kc)
|
||||
{
|
||||
mKc = kc;
|
||||
}
|
|
@ -1,302 +0,0 @@
|
|||
#include <nx/AciHeader.h>
|
||||
|
||||
nx::AciHeader::AciHeader()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
nx::AciHeader::AciHeader(const AciHeader & other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void nx::AciHeader::operator=(const AciHeader & other)
|
||||
{
|
||||
if (other.getBytes().size())
|
||||
{
|
||||
fromBytes(other.getBytes().data(), other.getBytes().size());
|
||||
}
|
||||
else
|
||||
{
|
||||
mHeaderOffset = other.mHeaderOffset;
|
||||
mType = other.mType;
|
||||
mIsProduction = other.mIsProduction;
|
||||
mIsUnqualifiedApproval = other.mIsUnqualifiedApproval;
|
||||
mAcidSize = other.mAcidSize;
|
||||
mProgramIdMin = other.mProgramIdMin;
|
||||
mProgramIdMax = other.mProgramIdMax;
|
||||
mProgramId = other.mProgramId;
|
||||
mFac = other.mFac;
|
||||
mSac = other.mSac;
|
||||
mKc = other.mKc;
|
||||
}
|
||||
}
|
||||
|
||||
bool nx::AciHeader::operator==(const AciHeader & other) const
|
||||
{
|
||||
return (mHeaderOffset == other.mHeaderOffset) \
|
||||
&& (mType == other.mType) \
|
||||
&& (mIsProduction == other.mIsProduction) \
|
||||
&& (mIsUnqualifiedApproval == other.mIsUnqualifiedApproval) \
|
||||
&& (mAcidSize == other.mAcidSize) \
|
||||
&& (mProgramIdMin == other.mProgramIdMin) \
|
||||
&& (mProgramIdMax == other.mProgramIdMax) \
|
||||
&& (mProgramId == other.mProgramId) \
|
||||
&& (mFac == other.mFac) \
|
||||
&& (mSac == other.mSac) \
|
||||
&& (mKc == other.mKc);
|
||||
}
|
||||
|
||||
bool nx::AciHeader::operator!=(const AciHeader & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nx::AciHeader::toBytes()
|
||||
{
|
||||
mRawBinary.alloc(sizeof(sAciHeader));
|
||||
sAciHeader* hdr = (sAciHeader*)mRawBinary.data();
|
||||
|
||||
// set type
|
||||
switch (mType)
|
||||
{
|
||||
case (TYPE_ACI0):
|
||||
hdr->st_magic = aci::kAciStructMagic;
|
||||
break;
|
||||
case (TYPE_ACID):
|
||||
hdr->st_magic = aci::kAciDescStructMagic;
|
||||
break;
|
||||
default:
|
||||
throw fnd::Exception(kModuleName, "Unexpected ACI type");
|
||||
}
|
||||
|
||||
// set offset/size
|
||||
calculateSectionOffsets();
|
||||
hdr->fac.offset = (uint32_t)mFac.offset;
|
||||
hdr->fac.size = (uint32_t)mFac.size;
|
||||
hdr->sac.offset = (uint32_t)mSac.offset;
|
||||
hdr->sac.size = (uint32_t)mSac.size;
|
||||
hdr->kc.offset = (uint32_t)mKc.offset;
|
||||
hdr->kc.size = (uint32_t)mKc.size;
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (mIsProduction)
|
||||
flags |= _BIT(aci::FLAG_PRODUCTION);
|
||||
if (mIsUnqualifiedApproval)
|
||||
flags |= _BIT(aci::FLAG_UNQUALIFIED_APPROVAL);
|
||||
|
||||
hdr->flags = flags;
|
||||
|
||||
if (mType == TYPE_ACI0)
|
||||
{
|
||||
// set program
|
||||
hdr->program_id_info.program_id = mProgramId;
|
||||
}
|
||||
else if (mType == TYPE_ACID)
|
||||
{
|
||||
mAcidSize = getAciSize();
|
||||
hdr->size = (uint32_t)mAcidSize;
|
||||
hdr->program_id_info.program_id_restrict.min = mProgramIdMin;
|
||||
hdr->program_id_info.program_id_restrict.max = mProgramIdMax;
|
||||
}
|
||||
}
|
||||
|
||||
void nx::AciHeader::fromBytes(const byte_t * bytes, size_t len)
|
||||
{
|
||||
if (len < sizeof(sAciHeader))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "ACI header too small");
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
mRawBinary.alloc(sizeof(sAciHeader));
|
||||
memcpy(mRawBinary.data(), bytes, sizeof(sAciHeader));
|
||||
|
||||
sAciHeader* hdr = (sAciHeader*)mRawBinary.data();
|
||||
|
||||
switch (hdr->st_magic.get())
|
||||
{
|
||||
case (aci::kAciStructMagic):
|
||||
mType = TYPE_ACI0;
|
||||
break;
|
||||
case (aci::kAciDescStructMagic):
|
||||
mType = TYPE_ACID;
|
||||
break;
|
||||
default:
|
||||
throw fnd::Exception(kModuleName, "ACI header corrupt");
|
||||
}
|
||||
|
||||
|
||||
if (mType == TYPE_ACI0)
|
||||
{
|
||||
mProgramId = hdr->program_id_info.program_id.get();
|
||||
mIsProduction = false;
|
||||
mIsUnqualifiedApproval = false;
|
||||
mAcidSize = 0;
|
||||
mProgramIdMin = 0;
|
||||
mProgramIdMax = 0;
|
||||
}
|
||||
else if (mType == TYPE_ACID)
|
||||
{
|
||||
mProgramId = 0;
|
||||
mIsProduction = _HAS_BIT(hdr->flags.get(), aci::FLAG_PRODUCTION);
|
||||
mIsUnqualifiedApproval = _HAS_BIT(hdr->flags.get(), aci::FLAG_UNQUALIFIED_APPROVAL);
|
||||
mAcidSize = hdr->size.get();
|
||||
mProgramIdMin = hdr->program_id_info.program_id_restrict.min.get();
|
||||
mProgramIdMax = hdr->program_id_info.program_id_restrict.max.get();
|
||||
}
|
||||
|
||||
// the header offset is the _MIN(sac.offset, fac.offset, kc.offset) - sizeof(sHeader)
|
||||
mHeaderOffset = _MAX(_MIN(hdr->sac.offset.get(), _MIN(hdr->fac.offset.get(), hdr->kc.offset.get())), align(sizeof(sAciHeader), aci::kAciAlignSize)) - align(sizeof(sAciHeader), aci::kAciAlignSize);
|
||||
|
||||
mFac.offset = hdr->fac.offset.get() - mHeaderOffset;
|
||||
mFac.size = hdr->fac.size.get();
|
||||
mSac.offset = hdr->sac.offset.get() - mHeaderOffset;
|
||||
mSac.size = hdr->sac.size.get();
|
||||
mKc.offset = hdr->kc.offset.get() - mHeaderOffset;
|
||||
mKc.size = hdr->kc.size.get();
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nx::AciHeader::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
void nx::AciHeader::clear()
|
||||
{
|
||||
mRawBinary.clear();
|
||||
mHeaderOffset = 0;
|
||||
mType = TYPE_ACI0;
|
||||
mProgramId = 0;
|
||||
mProgramIdMin = 0;
|
||||
mProgramIdMax = 0;
|
||||
mAcidSize = 0;
|
||||
mIsProduction = false;
|
||||
mIsUnqualifiedApproval = false;
|
||||
mFac.offset = 0;
|
||||
mFac.size = 0;
|
||||
mSac.offset = 0;
|
||||
mSac.size = 0;
|
||||
mKc.offset = 0;
|
||||
mKc.size = 0;
|
||||
}
|
||||
|
||||
size_t nx::AciHeader::getAciSize() const
|
||||
{
|
||||
return _MAX(_MAX(_MAX(mSac.offset + mSac.size, mKc.offset + mKc.size), mFac.offset + mFac.size), sizeof(sAciHeader));
|
||||
}
|
||||
|
||||
size_t nx::AciHeader::getAcidSize() const
|
||||
{
|
||||
return mAcidSize;
|
||||
}
|
||||
|
||||
/*
|
||||
void nx::AciHeader::setAcidSize(size_t size)
|
||||
{
|
||||
mAcidSize = size;
|
||||
}
|
||||
*/
|
||||
|
||||
uint64_t nx::AciHeader::getProgramIdMin() const
|
||||
{
|
||||
return mProgramIdMin;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setProgramIdMin(uint64_t program_id)
|
||||
{
|
||||
mProgramIdMin = program_id;
|
||||
}
|
||||
|
||||
uint64_t nx::AciHeader::getProgramIdMax() const
|
||||
{
|
||||
return mProgramIdMax;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setProgramIdMax(uint64_t program_id)
|
||||
{
|
||||
mProgramIdMax = program_id;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setHeaderOffset(size_t offset)
|
||||
{
|
||||
mHeaderOffset = offset;
|
||||
}
|
||||
|
||||
nx::AciHeader::AciType nx::AciHeader::getAciType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setAciType(AciType type)
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
bool nx::AciHeader::isProduction() const
|
||||
{
|
||||
return mIsProduction;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setIsProduction(bool isProduction)
|
||||
{
|
||||
mIsProduction = isProduction;
|
||||
}
|
||||
|
||||
bool nx::AciHeader::isUnqualifiedApproval() const
|
||||
{
|
||||
return mIsUnqualifiedApproval;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setIsUnqualifiedApproval(bool isUnqualifiedApproval)
|
||||
{
|
||||
mIsUnqualifiedApproval = isUnqualifiedApproval;
|
||||
}
|
||||
|
||||
uint64_t nx::AciHeader::getProgramId() const
|
||||
{
|
||||
return mProgramId;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setProgramId(uint64_t program_id)
|
||||
{
|
||||
mProgramId = program_id;
|
||||
}
|
||||
|
||||
const nx::AciHeader::sSection & nx::AciHeader::getFacPos() const
|
||||
{
|
||||
return mFac;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setFacSize(size_t size)
|
||||
{
|
||||
mFac.size = size;
|
||||
}
|
||||
|
||||
const nx::AciHeader::sSection & nx::AciHeader::getSacPos() const
|
||||
{
|
||||
return mSac;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setSacSize(size_t size)
|
||||
{
|
||||
mSac.size = size;
|
||||
}
|
||||
|
||||
const nx::AciHeader::sSection & nx::AciHeader::getKcPos() const
|
||||
{
|
||||
return mKc;
|
||||
}
|
||||
|
||||
void nx::AciHeader::setKcSize(size_t size)
|
||||
{
|
||||
mKc.size = size;
|
||||
}
|
||||
|
||||
void nx::AciHeader::calculateSectionOffsets()
|
||||
{
|
||||
mFac.offset = align(mHeaderOffset, aci::kAciAlignSize) + align(sizeof(sAciHeader), aci::kAciAlignSize);
|
||||
mSac.offset = mFac.offset + align(mFac.size, aci::kAciAlignSize);
|
||||
mKc.offset = mSac.offset + align(mSac.size, aci::kAciAlignSize);
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
#include <nx/AcidBinary.h>
|
||||
|
||||
nx::AcidBinary::AcidBinary()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
nx::AcidBinary::AcidBinary(const AcidBinary & other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool nx::AcidBinary::operator==(const AcidBinary & other) const
|
||||
{
|
||||
return AciBinary::operator==(other) \
|
||||
&& (mEmbeddedPublicKey == other.mEmbeddedPublicKey);
|
||||
}
|
||||
|
||||
bool nx::AcidBinary::operator!=(const AcidBinary & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void nx::AcidBinary::operator=(const AcidBinary & other)
|
||||
{
|
||||
if (other.getBytes().size())
|
||||
{
|
||||
fromBytes(other.getBytes().data(), other.getBytes().size());
|
||||
}
|
||||
else
|
||||
{
|
||||
AciBinary::operator=(other);
|
||||
mEmbeddedPublicKey = other.mEmbeddedPublicKey;
|
||||
}
|
||||
}
|
||||
|
||||
void nx::AcidBinary::toBytes()
|
||||
{
|
||||
AciBinary::setHeaderOffset(crypto::rsa::kRsa2048Size); // not include signature
|
||||
AciBinary::toBytes();
|
||||
mRawBinary.alloc(AciBinary::getBytes().size() + crypto::rsa::kRsa2048Size * 2);
|
||||
|
||||
memcpy(mRawBinary.data() + crypto::rsa::kRsa2048Size, mEmbeddedPublicKey.modulus, crypto::rsa::kRsa2048Size);
|
||||
memcpy(mRawBinary.data() + crypto::rsa::kRsa2048Size * 2, AciBinary::getBytes().data(), AciBinary::getBytes().size());
|
||||
}
|
||||
|
||||
void nx::AcidBinary::signBinary(const crypto::rsa::sRsa2048Key & key)
|
||||
{
|
||||
if (mRawBinary.size() == 0)
|
||||
{
|
||||
toBytes();
|
||||
}
|
||||
|
||||
byte_t hash[crypto::sha::kSha256HashLen];
|
||||
crypto::sha::Sha256(mRawBinary.data() + crypto::rsa::kRsa2048Size, mRawBinary.size() - crypto::rsa::kRsa2048Size, hash);
|
||||
|
||||
if (crypto::rsa::pkcs::rsaSign(key, crypto::sha::HASH_SHA256, hash, mRawBinary.data()) != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Failed to sign ACID");
|
||||
}
|
||||
}
|
||||
|
||||
void nx::AcidBinary::fromBytes(const byte_t * bytes, size_t len)
|
||||
{
|
||||
if (len <= crypto::rsa::kRsa2048Size*2)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "ACID binary too small");
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
// import aci binary past sig + pubkey
|
||||
AciBinary::fromBytes(bytes + crypto::rsa::kRsa2048Size * 2, len - crypto::rsa::kRsa2048Size * 2);
|
||||
|
||||
// save internal copy
|
||||
size_t acid_size = AciBinary::getBytes().size() + crypto::rsa::kRsa2048Size * 2;
|
||||
if (acid_size > len)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "ACID binary too small");
|
||||
}
|
||||
|
||||
mRawBinary.alloc(acid_size);
|
||||
memcpy(mRawBinary.data(), bytes, mRawBinary.size());
|
||||
memcpy(mEmbeddedPublicKey.modulus, bytes + crypto::rsa::kRsa2048Size, crypto::rsa::kRsa2048Size);
|
||||
}
|
||||
|
||||
void nx::AcidBinary::verifyBinary(const crypto::rsa::sRsa2048Key & key) const
|
||||
{
|
||||
if (mRawBinary.size() == 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No ACID binary exists to verify");
|
||||
}
|
||||
|
||||
byte_t hash[crypto::sha::kSha256HashLen];
|
||||
crypto::sha::Sha256(mRawBinary.data() + crypto::rsa::kRsa2048Size, mRawBinary.size() - crypto::rsa::kRsa2048Size, hash);
|
||||
|
||||
if (crypto::rsa::pss::rsaVerify(key, crypto::sha::HASH_SHA256, hash, mRawBinary.data()) != 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Failed to verify ACID");
|
||||
}
|
||||
}
|
||||
|
||||
const fnd::Vec<byte_t>& nx::AcidBinary::getBytes() const
|
||||
{
|
||||
return mRawBinary;
|
||||
}
|
||||
|
||||
void nx::AcidBinary::clear()
|
||||
{
|
||||
AciBinary::clear();
|
||||
mRawBinary.clear();
|
||||
mEmbeddedPublicKey = crypto::rsa::sRsa2048Key();
|
||||
}
|
||||
|
||||
const crypto::rsa::sRsa2048Key & nx::AcidBinary::getNcaHeader2RsaKey() const
|
||||
{
|
||||
return mEmbeddedPublicKey;
|
||||
}
|
||||
|
||||
void nx::AcidBinary::setNcaHeader2RsaKey(const crypto::rsa::sRsa2048Key & key)
|
||||
{
|
||||
mEmbeddedPublicKey = key;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#include <nx/NpdmBinary.h>
|
||||
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
|
||||
nx::NpdmBinary::NpdmBinary() :
|
||||
mAci(),
|
||||
mAcid()
|
||||
|
@ -42,11 +44,7 @@ bool nx::NpdmBinary::operator!=(const NpdmBinary & other) const
|
|||
|
||||
void nx::NpdmBinary::toBytes()
|
||||
{
|
||||
mAci.toBytes();
|
||||
mAcid.toBytes();
|
||||
|
||||
setAciSize(mAci.getBytes().size());
|
||||
setAcidSize(mAcid.getBytes().size());
|
||||
throw fnd::Exception(kModuleName, "toBytes() not implemented.");
|
||||
}
|
||||
|
||||
void nx::NpdmBinary::fromBytes(const byte_t* data, size_t len)
|
||||
|
@ -90,22 +88,22 @@ void nx::NpdmBinary::clear()
|
|||
mAcid.clear();
|
||||
}
|
||||
|
||||
const nx::AciBinary & nx::NpdmBinary::getAci() const
|
||||
const nx::AccessControlInfoBinary & nx::NpdmBinary::getAci() const
|
||||
{
|
||||
return mAci;
|
||||
}
|
||||
|
||||
void nx::NpdmBinary::setAci(const AciBinary & aci)
|
||||
void nx::NpdmBinary::setAci(const AccessControlInfoBinary & aci)
|
||||
{
|
||||
mAci = aci;
|
||||
}
|
||||
|
||||
const nx::AcidBinary & nx::NpdmBinary::getAcid() const
|
||||
const nx::AccessControlInfoDescBinary & nx::NpdmBinary::getAcid() const
|
||||
{
|
||||
return mAcid;
|
||||
}
|
||||
|
||||
void nx::NpdmBinary::setAcid(const AcidBinary & acid)
|
||||
void nx::NpdmBinary::setAcid(const AccessControlInfoDescBinary & acid)
|
||||
{
|
||||
mAcid = acid;
|
||||
}
|
|
@ -618,7 +618,7 @@ void NcaProcess::validateNcaSignatures()
|
|||
npdm.setCliOutputMode(0);
|
||||
npdm.process();
|
||||
|
||||
if (crypto::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeader2RsaKey(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
|
||||
if (crypto::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeaderSignature2Key(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
|
||||
{
|
||||
printf("[WARNING] NCA Header ACID Signature: FAIL \n");
|
||||
}
|
||||
|
|
|
@ -44,17 +44,17 @@ void NpdmProcess::process()
|
|||
|
||||
// aci binary
|
||||
displayAciHdr(mNpdm.getAci());
|
||||
displayFac(mNpdm.getAci().getFac());
|
||||
displaySac(mNpdm.getAci().getSac());
|
||||
displayKernelCap(mNpdm.getAci().getKc());
|
||||
displayFac(mNpdm.getAci().getFileSystemAccessControl());
|
||||
displaySac(mNpdm.getAci().getServiceAccessControl());
|
||||
displayKernelCap(mNpdm.getAci().getKernelCapabilities());
|
||||
|
||||
// acid binary
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
displayAciHdr(mNpdm.getAcid());
|
||||
displayFac(mNpdm.getAcid().getFac());
|
||||
displaySac(mNpdm.getAcid().getSac());
|
||||
displayKernelCap(mNpdm.getAcid().getKc());
|
||||
displayAciDescHdr(mNpdm.getAcid());
|
||||
displayFac(mNpdm.getAcid().getFileSystemAccessControl());
|
||||
displaySac(mNpdm.getAcid().getServiceAccessControl());
|
||||
displayKernelCap(mNpdm.getAcid().getKernelCapabilities());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,41 @@ const nx::NpdmBinary& NpdmProcess::getNpdmBinary() const
|
|||
|
||||
const std::string kInstructionType[2] = { "32Bit", "64Bit" };
|
||||
const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" };
|
||||
const std::string kAciType[2] = { "ACI0", "ACID" };
|
||||
const std::string kAcidFlag[32] =
|
||||
{
|
||||
"Production",
|
||||
"UnqualifiedApproval",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown",
|
||||
"Unknown"
|
||||
};
|
||||
const std::string kMiscFlag[15] = { "EnableDebug", "ForceDebug", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7", "bit8", "bit9", "bit10", "bit11", "bit12", "bit13", "bit14"};
|
||||
const std::string kFsaFlag[64] =
|
||||
{
|
||||
|
@ -293,10 +327,10 @@ const std::string kMemMapType[2] = { "Io", "Static" };
|
|||
|
||||
const std::string kAcidTarget[2] = { "Development", "Production" };
|
||||
|
||||
void NpdmProcess::validateAcidSignature(const nx::AcidBinary& acid)
|
||||
void NpdmProcess::validateAcidSignature(const nx::AccessControlInfoDescBinary& acid)
|
||||
{
|
||||
try {
|
||||
acid.verifyBinary(mKeyset->acid_sign_key);
|
||||
acid.validateSignature(mKeyset->acid_sign_key);
|
||||
}
|
||||
catch (...) {
|
||||
printf("[WARNING] ACID Signature: FAIL\n");
|
||||
|
@ -304,193 +338,193 @@ void NpdmProcess::validateAcidSignature(const nx::AcidBinary& acid)
|
|||
|
||||
}
|
||||
|
||||
void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBinary& acid)
|
||||
void NpdmProcess::validateAciFromAcid(const nx::AccessControlInfoBinary& aci, const nx::AccessControlInfoDescBinary& acid)
|
||||
{
|
||||
// check Program ID
|
||||
if (acid.getProgramIdMin() > 0 && aci.getProgramId() < acid.getProgramIdMin())
|
||||
if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min)
|
||||
{
|
||||
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
|
||||
}
|
||||
else if (acid.getProgramIdMax() > 0 && aci.getProgramId() > acid.getProgramIdMax())
|
||||
else if (acid.getProgramIdRestrict().max > 0 && aci.getProgramId() > acid.getProgramIdRestrict().max)
|
||||
{
|
||||
printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aci.getFac().getFsaRightsList().size(); i++)
|
||||
for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++)
|
||||
{
|
||||
bool fsaRightFound = false;
|
||||
for (size_t j = 0; j < acid.getFac().getFsaRightsList().size() && fsaRightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getFileSystemAccessControl().getFsaRightsList().size() && fsaRightFound == false; j++)
|
||||
{
|
||||
if (aci.getFac().getFsaRightsList()[i] == acid.getFac().getFsaRightsList()[j])
|
||||
if (aci.getFileSystemAccessControl().getFsaRightsList()[i] == acid.getFileSystemAccessControl().getFsaRightsList()[j])
|
||||
fsaRightFound = true;
|
||||
}
|
||||
|
||||
if (fsaRightFound == false)
|
||||
{
|
||||
|
||||
printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFac().getFsaRightsList()[i]].c_str());
|
||||
printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFileSystemAccessControl().getFsaRightsList()[i]].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aci.getFac().getContentOwnerIdList().size(); i++)
|
||||
for (size_t i = 0; i < aci.getFileSystemAccessControl().getContentOwnerIdList().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getFac().getContentOwnerIdList().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getFileSystemAccessControl().getContentOwnerIdList().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getFac().getContentOwnerIdList()[i] == acid.getFac().getContentOwnerIdList()[j])
|
||||
if (aci.getFileSystemAccessControl().getContentOwnerIdList()[i] == acid.getFileSystemAccessControl().getContentOwnerIdList()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
|
||||
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getContentOwnerIdList()[i]);
|
||||
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFileSystemAccessControl().getContentOwnerIdList()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aci.getFac().getSaveDataOwnerIdList().size(); i++)
|
||||
for (size_t i = 0; i < aci.getFileSystemAccessControl().getSaveDataOwnerIdList().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getFac().getSaveDataOwnerIdList().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getFileSystemAccessControl().getSaveDataOwnerIdList().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getFac().getSaveDataOwnerIdList()[i] == acid.getFac().getSaveDataOwnerIdList()[j])
|
||||
if (aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i] == acid.getFileSystemAccessControl().getSaveDataOwnerIdList()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
|
||||
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getSaveDataOwnerIdList()[i]);
|
||||
printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// check SAC
|
||||
for (size_t i = 0; i < aci.getSac().getServiceList().size(); i++)
|
||||
for (size_t i = 0; i < aci.getServiceAccessControl().getServiceList().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getSac().getServiceList().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getServiceAccessControl().getServiceList().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getSac().getServiceList()[i] == acid.getSac().getServiceList()[j])
|
||||
if (aci.getServiceAccessControl().getServiceList()[i] == acid.getServiceAccessControl().getServiceList()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getSac().getServiceList()[i].getName().c_str(), aci.getSac().getServiceList()[i].isServer()? " (Server)" : "");
|
||||
printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getServiceAccessControl().getServiceList()[i].getName().c_str(), aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
// check KC
|
||||
// check thread info
|
||||
if (aci.getKc().getThreadInfo().getMaxCpuId() != acid.getKc().getThreadInfo().getMaxCpuId())
|
||||
if (aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() != acid.getKernelCapabilities().getThreadInfo().getMaxCpuId())
|
||||
{
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxCpuId());
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxCpuId());
|
||||
}
|
||||
if (aci.getKc().getThreadInfo().getMinCpuId() != acid.getKc().getThreadInfo().getMinCpuId())
|
||||
if (aci.getKernelCapabilities().getThreadInfo().getMinCpuId() != acid.getKernelCapabilities().getThreadInfo().getMinCpuId())
|
||||
{
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinCpuId());
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinCpuId());
|
||||
}
|
||||
if (aci.getKc().getThreadInfo().getMaxPriority() != acid.getKc().getThreadInfo().getMaxPriority())
|
||||
if (aci.getKernelCapabilities().getThreadInfo().getMaxPriority() != acid.getKernelCapabilities().getThreadInfo().getMaxPriority())
|
||||
{
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxPriority());
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxPriority());
|
||||
}
|
||||
if (aci.getKc().getThreadInfo().getMinPriority() != acid.getKc().getThreadInfo().getMinPriority())
|
||||
if (aci.getKernelCapabilities().getThreadInfo().getMinPriority() != acid.getKernelCapabilities().getThreadInfo().getMinPriority())
|
||||
{
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinPriority());
|
||||
printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinPriority());
|
||||
}
|
||||
// check system calls
|
||||
for (size_t i = 0; i < aci.getKc().getSystemCalls().getSystemCalls().size(); i++)
|
||||
for (size_t i = 0; i < aci.getKernelCapabilities().getSystemCalls().getSystemCalls().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getKc().getSystemCalls().getSystemCalls().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getKernelCapabilities().getSystemCalls().getSystemCalls().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getKc().getSystemCalls().getSystemCalls()[i] == acid.getKc().getSystemCalls().getSystemCalls()[j])
|
||||
if (aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i] == acid.getKernelCapabilities().getSystemCalls().getSystemCalls()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKc().getSystemCalls().getSystemCalls()[i]].c_str());
|
||||
printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]].c_str());
|
||||
}
|
||||
}
|
||||
// check memory maps
|
||||
for (size_t i = 0; i < aci.getKc().getMemoryMaps().getMemoryMaps().size(); i++)
|
||||
for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getKc().getMemoryMaps().getMemoryMaps().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getKernelCapabilities().getMemoryMaps().getMemoryMaps().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getKc().getMemoryMaps().getMemoryMaps()[i] == acid.getKc().getMemoryMaps().getMemoryMaps()[j])
|
||||
if (aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i] == acid.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getMemoryMaps()[i];
|
||||
const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i];
|
||||
|
||||
printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str());
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < aci.getKc().getMemoryMaps().getIoMemoryMaps().size(); i++)
|
||||
for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getKc().getMemoryMaps().getIoMemoryMaps().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getKc().getMemoryMaps().getIoMemoryMaps()[i] == acid.getKc().getMemoryMaps().getIoMemoryMaps()[j])
|
||||
if (aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i] == acid.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getIoMemoryMaps()[i];
|
||||
const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i];
|
||||
|
||||
printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str());
|
||||
}
|
||||
}
|
||||
// check interupts
|
||||
for (size_t i = 0; i < aci.getKc().getInterupts().getInteruptList().size(); i++)
|
||||
for (size_t i = 0; i < aci.getKernelCapabilities().getInterupts().getInteruptList().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getKc().getInterupts().getInteruptList().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getKernelCapabilities().getInterupts().getInteruptList().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getKc().getInterupts().getInteruptList()[i] == acid.getKc().getInterupts().getInteruptList()[j])
|
||||
if (aci.getKernelCapabilities().getInterupts().getInteruptList()[i] == acid.getKernelCapabilities().getInterupts().getInteruptList()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKc().getInterupts().getInteruptList()[i]);
|
||||
printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKernelCapabilities().getInterupts().getInteruptList()[i]);
|
||||
}
|
||||
}
|
||||
// check misc params
|
||||
if (aci.getKc().getMiscParams().getProgramType() != acid.getKc().getMiscParams().getProgramType())
|
||||
if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType())
|
||||
{
|
||||
printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKc().getMiscParams().getProgramType());
|
||||
printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType());
|
||||
}
|
||||
// check kernel version
|
||||
uint32_t aciKernelVersion = (uint32_t)aci.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKc().getKernelVersion().getVerMinor();
|
||||
uint32_t acidKernelVersion = (uint32_t)acid.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKc().getKernelVersion().getVerMinor();
|
||||
uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor();
|
||||
uint32_t acidKernelVersion = (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMinor();
|
||||
if (aciKernelVersion < acidKernelVersion)
|
||||
{
|
||||
printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKc().getKernelVersion().getVerMajor(), aci.getKc().getKernelVersion().getVerMinor());
|
||||
printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKernelCapabilities().getKernelVersion().getVerMajor(), aci.getKernelCapabilities().getKernelVersion().getVerMinor());
|
||||
}
|
||||
// check handle table size
|
||||
if (aci.getKc().getHandleTableSize().getHandleTableSize() > acid.getKc().getHandleTableSize().getHandleTableSize())
|
||||
if (aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() > acid.getKernelCapabilities().getHandleTableSize().getHandleTableSize())
|
||||
{
|
||||
printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKc().getHandleTableSize().getHandleTableSize());
|
||||
printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize());
|
||||
}
|
||||
// check misc flags
|
||||
for (size_t i = 0; i < aci.getKc().getMiscFlags().getFlagList().size(); i++)
|
||||
for (size_t i = 0; i < aci.getKernelCapabilities().getMiscFlags().getFlagList().size(); i++)
|
||||
{
|
||||
bool rightFound = false;
|
||||
for (size_t j = 0; j < acid.getKc().getMiscFlags().getFlagList().size() && rightFound == false; j++)
|
||||
for (size_t j = 0; j < acid.getKernelCapabilities().getMiscFlags().getFlagList().size() && rightFound == false; j++)
|
||||
{
|
||||
if (aci.getKc().getMiscFlags().getFlagList()[i] == acid.getKc().getMiscFlags().getFlagList()[j])
|
||||
if (aci.getKernelCapabilities().getMiscFlags().getFlagList()[i] == acid.getKernelCapabilities().getMiscFlags().getFlagList()[j])
|
||||
rightFound = true;
|
||||
}
|
||||
|
||||
if (rightFound == false)
|
||||
{
|
||||
printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKc().getMiscFlags().getFlagList()[i]].c_str());
|
||||
printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,26 +548,26 @@ void NpdmProcess::displayNpdmHeader(const nx::NpdmHeader& hdr)
|
|||
}
|
||||
}
|
||||
|
||||
void NpdmProcess::displayAciHdr(const nx::AciHeader& aci)
|
||||
void NpdmProcess::displayAciHdr(const nx::AccessControlInfoBinary& aci)
|
||||
{
|
||||
printf("[Access Control Info]\n");
|
||||
printf(" ACI Type: %s\n", kAciType[aci.getAciType()].c_str());
|
||||
if (aci.getAciType() == nx::AciBinary::TYPE_ACI0)
|
||||
{
|
||||
printf(" ProgramID: %016" PRIx64 "\n", aci.getProgramId());
|
||||
}
|
||||
else if (aci.getAciType() == nx::AciBinary::TYPE_ACID)
|
||||
{
|
||||
printf(" ProgramID: 0x%016" PRIx64 "\n", aci.getProgramId());
|
||||
}
|
||||
|
||||
printf(" ACID Size: %" PRIx64 "\n", (uint64_t)aci.getAcidSize());
|
||||
void NpdmProcess::displayAciDescHdr(const nx::AccessControlInfoDescBinary& acid)
|
||||
{
|
||||
printf("[Access Control Info Desc]\n");
|
||||
if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
printf(" Flags: \n");
|
||||
printf(" Production: %s\n", aci.isProduction() ? "TRUE" : "FALSE");
|
||||
printf(" UnqualifiedApproval: %s\n", aci.isUnqualifiedApproval() ? "TRUE" : "FALSE");
|
||||
printf(" ProgramID Restriction\n");
|
||||
printf(" Min: %016" PRIx64 "\n", aci.getProgramIdMin());
|
||||
printf(" Max: %016" PRIx64 "\n", aci.getProgramIdMax());
|
||||
|
||||
for (size_t i = 0; i < acid.getFlagList().size(); i++)
|
||||
{
|
||||
printf(" %s (%d)\n", kAcidFlag[acid.getFlagList()[i]].c_str(), acid.getFlagList()[i]);
|
||||
}
|
||||
}
|
||||
printf(" ProgramID Restriction\n");
|
||||
printf(" Min: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().min);
|
||||
printf(" Max: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().max);
|
||||
}
|
||||
|
||||
void NpdmProcess::displayFac(const nx::FacBinary& fac)
|
||||
|
|
|
@ -32,11 +32,12 @@ private:
|
|||
|
||||
nx::NpdmBinary mNpdm;
|
||||
|
||||
void validateAcidSignature(const nx::AcidBinary& acid);
|
||||
void validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBinary& acid);
|
||||
void validateAcidSignature(const nx::AccessControlInfoDescBinary& acid);
|
||||
void validateAciFromAcid(const nx::AccessControlInfoBinary& aci, const nx::AccessControlInfoDescBinary& acid);
|
||||
|
||||
void displayNpdmHeader(const nx::NpdmHeader& hdr);
|
||||
void displayAciHdr(const nx::AciHeader& aci);
|
||||
void displayAciHdr(const nx::AccessControlInfoBinary& aci);
|
||||
void displayAciDescHdr(const nx::AccessControlInfoDescBinary& aci);
|
||||
void displayFac(const nx::FacBinary& fac);
|
||||
void displaySac(const nx::SacBinary& sac);
|
||||
void displayKernelCap(const nx::KcBinary& kern);
|
||||
|
|
Loading…
Reference in a new issue