mirror of
https://github.com/jakcron/nstool
synced 2024-11-22 21:49:30 +00:00
Merge pull request #40 from jakcron/nstool-esfiletypes
Implement nstool support for .tik and .cert
This commit is contained in:
commit
af94654a2d
42 changed files with 1684 additions and 320 deletions
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
|
@ -10,8 +10,10 @@
|
||||||
"/usr/include",
|
"/usr/include",
|
||||||
"${workspaceRoot}",
|
"${workspaceRoot}",
|
||||||
"${workspaceRoot}/lib/libcrypto/include",
|
"${workspaceRoot}/lib/libcrypto/include",
|
||||||
|
"${workspaceRoot}/lib/libcrypto/source/polarssl/libinclude",
|
||||||
"${workspaceRoot}/lib/libcompress/include",
|
"${workspaceRoot}/lib/libcompress/include",
|
||||||
"${workspaceRoot}/lib/libes/include",
|
"${workspaceRoot}/lib/libes/include",
|
||||||
|
"${workspaceRoot}/lib/libpki/include",
|
||||||
"${workspaceRoot}/lib/libfnd/include",
|
"${workspaceRoot}/lib/libfnd/include",
|
||||||
"${workspaceRoot}/lib/libnx/include",
|
"${workspaceRoot}/lib/libnx/include",
|
||||||
"${workspaceRoot}/lib/libnx-hb/include"
|
"${workspaceRoot}/lib/libnx-hb/include"
|
||||||
|
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
@ -27,7 +27,14 @@
|
||||||
"memory": "cpp",
|
"memory": "cpp",
|
||||||
"tuple": "cpp",
|
"tuple": "cpp",
|
||||||
"__locale": "cpp",
|
"__locale": "cpp",
|
||||||
"cinttypes": "cpp"
|
"cinttypes": "cpp",
|
||||||
"__bit_reference": "cpp",
|
"__bit_reference": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"__functional_base_03": "cpp",
|
||||||
|
"__tuple": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"ratio": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
4
KEYS.md
4
KEYS.md
|
@ -25,6 +25,10 @@ package2_sign_key_private : RSA2048 Private Exponent (0x100 bytes)
|
||||||
; Ticket Keys
|
; Ticket Keys
|
||||||
ticket_commonkey_## : AES128 Key (0x10 bytes)
|
ticket_commonkey_## : AES128 Key (0x10 bytes)
|
||||||
|
|
||||||
|
; PKI Root Signing Key
|
||||||
|
pki_root_sign_key_modulus : RSA4096 Modulus (0x200 bytes)
|
||||||
|
pki_root_sign_key_private : RSA4096 Private Exponent (0x200 bytes)
|
||||||
|
|
||||||
; NCA Keys
|
; NCA Keys
|
||||||
nca_header_key : AES128-XTS Key (0x20 bytes)
|
nca_header_key : AES128-XTS Key (0x20 bytes)
|
||||||
nca_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes)
|
nca_header_sign_key_modulus : RSA2048 Modulus (0x100 bytes)
|
||||||
|
|
11
NXTools.sln
11
NXTools.sln
|
@ -44,6 +44,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcompress", "lib\libcompr
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnx-hb", "lib\libnx-hb\libnx-hb.vcxproj", "{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnx-hb", "lib\libnx-hb\libnx-hb.vcxproj", "{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpki", "lib\libpki\libpki.vcxproj", "{B9113734-6E84-44FF-8CF7-58199AA815C5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
|
@ -108,6 +110,14 @@ Global
|
||||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x64.Build.0 = Release|x64
|
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x64.Build.0 = Release|x64
|
||||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.ActiveCfg = Release|Win32
|
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.Build.0 = Release|Win32
|
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Release|x64.Build.0 = Release|x64
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5}.Release|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -120,6 +130,7 @@ Global
|
||||||
{AF09FA96-4463-417D-8FE6-526063F41349} = {E0863FCC-8E72-490D-BE1B-458F12CA8298}
|
{AF09FA96-4463-417D-8FE6-526063F41349} = {E0863FCC-8E72-490D-BE1B-458F12CA8298}
|
||||||
{CF01B5B7-730A-447F-9BB2-5EDA9B082177} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
{CF01B5B7-730A-447F-9BB2-5EDA9B082177} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||||
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
{738CB4FC-CD9E-4B81-A04B-DEADBFA71C63} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||||
|
{B9113734-6E84-44FF-8CF7-58199AA815C5} = {170B4A09-1B67-4A62-93AB-116EBCFF4A8C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {07DCCACC-D10D-47C9-85AE-FB9C54DB7D62}
|
SolutionGuid = {07DCCACC-D10D-47C9-85AE-FB9C54DB7D62}
|
||||||
|
|
|
@ -13,9 +13,10 @@ Tools & Libraries for NX (Nintendo Switch).
|
||||||
* __libfnd__ - Foundation library.
|
* __libfnd__ - Foundation library.
|
||||||
* __libcrypto__ - Cryptographic functions (AES,SHA,RSA). Wrapper for [mbedTLS](https://github.com/ARMmbed/mbedtls)
|
* __libcrypto__ - Cryptographic functions (AES,SHA,RSA). Wrapper for [mbedTLS](https://github.com/ARMmbed/mbedtls)
|
||||||
* __libcompress__ - Compression algorithms (LZ4). Wrapper for [lz4](https://github.com/lz4/lz4)
|
* __libcompress__ - Compression algorithms (LZ4). Wrapper for [lz4](https://github.com/lz4/lz4)
|
||||||
* __libes__ - Handling of (NX relevant) eShop file type processing. (eTickets, etc)
|
* __libpki__ - Processes Nintendo's proprietary PKI.
|
||||||
* __libnx__ - Handling of NX file types.
|
* __libes__ - Processes Nintendo's eShop file types.
|
||||||
* __libnx-hb__ - Handling of NX (homebrew extensions) file types.
|
* __libnx__ - Processes NX file types.
|
||||||
|
* __libnx-hb__ - Processes NX file types (homebrew extensions).
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="include\crypto\aes.h" />
|
<ClInclude Include="include\crypto\aes.h" />
|
||||||
|
<ClInclude Include="include\crypto\base64.h" />
|
||||||
<ClInclude Include="include\crypto\ecdsa.h" />
|
<ClInclude Include="include\crypto\ecdsa.h" />
|
||||||
<ClInclude Include="include\crypto\rsa.h" />
|
<ClInclude Include="include\crypto\rsa.h" />
|
||||||
<ClInclude Include="include\crypto\sha.h" />
|
<ClInclude Include="include\crypto\sha.h" />
|
||||||
|
@ -137,6 +138,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\aes_wrapper.cpp" />
|
<ClCompile Include="source\aes_wrapper.cpp" />
|
||||||
|
<ClCompile Include="source\base64_wrapper.cpp" />
|
||||||
<ClCompile Include="source\libpolarssl\source\aes.c" />
|
<ClCompile Include="source\libpolarssl\source\aes.c" />
|
||||||
<ClCompile Include="source\libpolarssl\source\base64.c" />
|
<ClCompile Include="source\libpolarssl\source\base64.c" />
|
||||||
<ClCompile Include="source\libpolarssl\source\bignum.c" />
|
<ClCompile Include="source\libpolarssl\source\bignum.c" />
|
||||||
|
|
|
@ -66,6 +66,9 @@
|
||||||
<ClInclude Include="include\crypto\ecdsa.h">
|
<ClInclude Include="include\crypto\ecdsa.h">
|
||||||
<Filter>Header Files\crypto</Filter>
|
<Filter>Header Files\crypto</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\crypto\base64.h">
|
||||||
|
<Filter>Header Files\crypto</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\aes_wrapper.cpp">
|
<ClCompile Include="source\aes_wrapper.cpp">
|
||||||
|
@ -101,6 +104,9 @@
|
||||||
<ClCompile Include="source\libpolarssl\source\sha2.c">
|
<ClCompile Include="source\libpolarssl\source\sha2.c">
|
||||||
<Filter>Source Files\polarssl</Filter>
|
<Filter>Source Files\polarssl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\base64_wrapper.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="makefile" />
|
<None Include="makefile" />
|
||||||
|
|
14
lib/libcrypto/include/crypto/base64.h
Normal file
14
lib/libcrypto/include/crypto/base64.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace crypto
|
||||||
|
{
|
||||||
|
namespace base64
|
||||||
|
{
|
||||||
|
size_t B64_GetEncodeLen(const uint8_t* src, size_t slen);
|
||||||
|
void B64_Encode(const uint8_t* src, size_t slen, uint8_t* dst, size_t dlen);
|
||||||
|
size_t B64_GetDecodeLen(const uint8_t* src, size_t slen);
|
||||||
|
void B64_Decode(const uint8_t* src, size_t slen, uint8_t* dst, size_t dlen);
|
||||||
|
}
|
||||||
|
}
|
30
lib/libcrypto/source/base64_wrapper.cpp
Normal file
30
lib/libcrypto/source/base64_wrapper.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include <crypto/base64.h>
|
||||||
|
#include <polarssl/base64.h>
|
||||||
|
|
||||||
|
size_t crypto::base64::B64_GetEncodeLen(const uint8_t* src, size_t slen)
|
||||||
|
{
|
||||||
|
size_t dlen = 0;
|
||||||
|
|
||||||
|
base64_encode(nullptr, &dlen, src, slen);
|
||||||
|
|
||||||
|
return dlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto::base64::B64_Encode(const uint8_t* src, size_t slen, uint8_t* dst, size_t dlen)
|
||||||
|
{
|
||||||
|
base64_encode(dst, &dlen, src, slen);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t crypto::base64::B64_GetDecodeLen(const uint8_t* src, size_t slen)
|
||||||
|
{
|
||||||
|
size_t dlen = 0;
|
||||||
|
|
||||||
|
base64_decode(nullptr, &dlen, src, slen);
|
||||||
|
|
||||||
|
return dlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto::base64::B64_Decode(const uint8_t* src, size_t slen, uint8_t* dst, size_t dlen)
|
||||||
|
{
|
||||||
|
base64_decode(dst, &dlen, src, slen);
|
||||||
|
}
|
|
@ -122,21 +122,14 @@
|
||||||
<None Include="makefile" />
|
<None Include="makefile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\CertificateBody.cpp" />
|
|
||||||
<ClCompile Include="source\SectionHeader_V2.cpp" />
|
|
||||||
<ClCompile Include="source\SignatureBlock.cpp" />
|
|
||||||
<ClCompile Include="source\TicketBody_V2.cpp" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="include\es\cert.h" />
|
|
||||||
<ClInclude Include="include\es\CertificateBody.h" />
|
|
||||||
<ClInclude Include="include\es\SectionHeader_V2.h" />
|
<ClInclude Include="include\es\SectionHeader_V2.h" />
|
||||||
<ClInclude Include="include\es\sign.h" />
|
|
||||||
<ClInclude Include="include\es\SignatureBlock.h" />
|
|
||||||
<ClInclude Include="include\es\SignedData.h" />
|
|
||||||
<ClInclude Include="include\es\ticket.h" />
|
<ClInclude Include="include\es\ticket.h" />
|
||||||
<ClInclude Include="include\es\TicketBody_V2.h" />
|
<ClInclude Include="include\es\TicketBody_V2.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="source\SectionHeader_V2.cpp" />
|
||||||
|
<ClCompile Include="source\TicketBody_V2.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
|
|
@ -18,38 +18,9 @@
|
||||||
<None Include="makefile" />
|
<None Include="makefile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\CertificateBody.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\SectionHeader_V2.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\SignatureBlock.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\TicketBody_V2.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="include\es\cert.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="include\es\CertificateBody.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="include\es\SectionHeader_V2.h">
|
<ClInclude Include="include\es\SectionHeader_V2.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="include\es\sign.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="include\es\SignatureBlock.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="include\es\SignedData.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="include\es\ticket.h">
|
<ClInclude Include="include\es\ticket.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -57,4 +28,12 @@
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="source\SectionHeader_V2.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\TicketBody_V2.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/ISerialisable.h>
|
#include <fnd/ISerialisable.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
#include <es/ticket.h>
|
#include <es/ticket.h>
|
||||||
|
|
||||||
namespace es
|
namespace es
|
||||||
|
@ -42,14 +43,8 @@ namespace es
|
||||||
byte_t getCommonKeyId() const;
|
byte_t getCommonKeyId() const;
|
||||||
void setCommonKeyId(byte_t id);
|
void setCommonKeyId(byte_t id);
|
||||||
|
|
||||||
bool isPreInstall() const;
|
const fnd::List<es::ticket::PropertyMaskFlags>& getPropertyFlags() const;
|
||||||
void setIsPreInstall(bool isPreInstall);
|
void setPropertyFlags(const fnd::List<es::ticket::PropertyMaskFlags>& flags);
|
||||||
|
|
||||||
bool isSharedTitle() const;
|
|
||||||
void setIsSharedTitle(bool isSharedTitle);
|
|
||||||
|
|
||||||
bool allowAllContent() const;
|
|
||||||
void setAllowAllContent(bool allowAllContent);
|
|
||||||
|
|
||||||
const byte_t* getReservedRegion() const;
|
const byte_t* getReservedRegion() const;
|
||||||
void setReservedRegion(const byte_t* data, size_t len);
|
void setReservedRegion(const byte_t* data, size_t len);
|
||||||
|
@ -91,9 +86,7 @@ namespace es
|
||||||
uint16_t mTicketVersion;
|
uint16_t mTicketVersion;
|
||||||
ticket::LicenseType mLicenseType;
|
ticket::LicenseType mLicenseType;
|
||||||
byte_t mCommonKeyId;
|
byte_t mCommonKeyId;
|
||||||
bool mPreInstall;
|
fnd::List<es::ticket::PropertyMaskFlags> mPropertyFlags;
|
||||||
bool mSharedTitle;
|
|
||||||
bool mAllowAllContent;
|
|
||||||
byte_t mReservedRegion[ticket::kReservedRegionSize]; // explicitly reserved
|
byte_t mReservedRegion[ticket::kReservedRegionSize]; // explicitly reserved
|
||||||
uint64_t mTicketId;
|
uint64_t mTicketId;
|
||||||
uint64_t mDeviceId;
|
uint64_t mDeviceId;
|
||||||
|
|
|
@ -26,9 +26,8 @@ void es::TicketBody_V2::operator=(const TicketBody_V2 & other)
|
||||||
mEncType = other.mEncType;
|
mEncType = other.mEncType;
|
||||||
mTicketVersion = other.mTicketVersion;
|
mTicketVersion = other.mTicketVersion;
|
||||||
mLicenseType = other.mLicenseType;
|
mLicenseType = other.mLicenseType;
|
||||||
mPreInstall = other.mPreInstall;
|
mCommonKeyId = other.mCommonKeyId;
|
||||||
mSharedTitle = other.mSharedTitle;
|
mPropertyFlags = other.mPropertyFlags;
|
||||||
mAllowAllContent = other.mAllowAllContent;
|
|
||||||
memcpy(mReservedRegion, other.mReservedRegion, ticket::kReservedRegionSize);
|
memcpy(mReservedRegion, other.mReservedRegion, ticket::kReservedRegionSize);
|
||||||
mTicketId = other.mTicketId;
|
mTicketId = other.mTicketId;
|
||||||
mDeviceId = other.mDeviceId;
|
mDeviceId = other.mDeviceId;
|
||||||
|
@ -48,9 +47,7 @@ bool es::TicketBody_V2::operator==(const TicketBody_V2 & other) const
|
||||||
&& (mEncType == other.mEncType) \
|
&& (mEncType == other.mEncType) \
|
||||||
&& (mTicketVersion == other.mTicketVersion) \
|
&& (mTicketVersion == other.mTicketVersion) \
|
||||||
&& (mLicenseType == other.mLicenseType) \
|
&& (mLicenseType == other.mLicenseType) \
|
||||||
&& (mPreInstall == other.mPreInstall) \
|
&& (mPropertyFlags == other.mPropertyFlags) \
|
||||||
&& (mSharedTitle == other.mSharedTitle) \
|
|
||||||
&& (mAllowAllContent == other.mAllowAllContent) \
|
|
||||||
&& (memcmp(mReservedRegion, other.mReservedRegion, ticket::kReservedRegionSize) == 0) \
|
&& (memcmp(mReservedRegion, other.mReservedRegion, ticket::kReservedRegionSize) == 0) \
|
||||||
&& (mTicketId == other.mTicketId) \
|
&& (mTicketId == other.mTicketId) \
|
||||||
&& (mDeviceId == other.mDeviceId) \
|
&& (mDeviceId == other.mDeviceId) \
|
||||||
|
@ -74,19 +71,22 @@ void es::TicketBody_V2::toBytes()
|
||||||
|
|
||||||
body->format_version = (ticket::kFormatVersion);
|
body->format_version = (ticket::kFormatVersion);
|
||||||
|
|
||||||
strncmp(body->issuer, mIssuer.c_str(), ticket::kIssuerSize);
|
strncpy(body->issuer, mIssuer.c_str(), ticket::kIssuerSize);
|
||||||
memcpy(body->enc_title_key, mEncTitleKey, ticket::kEncTitleKeySize);
|
memcpy(body->enc_title_key, mEncTitleKey, ticket::kEncTitleKeySize);
|
||||||
body->title_key_enc_type = (mEncType);
|
body->title_key_enc_type = (mEncType);
|
||||||
body->ticket_version = (mTicketVersion);
|
body->ticket_version = (mTicketVersion);
|
||||||
|
body->license_type = mLicenseType;
|
||||||
|
body->common_key_id = mCommonKeyId;
|
||||||
byte_t property_mask = 0;
|
byte_t property_mask = 0;
|
||||||
property_mask |= mPreInstall ? _BIT(ticket::FLAG_PRE_INSTALL) : 0;
|
for (size_t i = 0; i < mPropertyFlags.size(); i++)
|
||||||
property_mask |= mSharedTitle ? _BIT(ticket::FLAG_SHARED_TITLE) : 0;
|
{
|
||||||
property_mask |= mAllowAllContent ? _BIT(ticket::FLAG_ALLOW_ALL_CONTENT) : 0;
|
property_mask |= _BIT(mPropertyFlags[i]);
|
||||||
|
}
|
||||||
body->property_mask = (property_mask);
|
body->property_mask = (property_mask);
|
||||||
memcpy(body->reserved_region, mReservedRegion, ticket::kReservedRegionSize);
|
memcpy(body->reserved_region, mReservedRegion, ticket::kReservedRegionSize);
|
||||||
body->ticket_id = (mTicketId);
|
body->ticket_id = (mTicketId);
|
||||||
body->device_id = (mDeviceId);
|
body->device_id = (mDeviceId);
|
||||||
memcmp(body->rights_id, mRightsId, ticket::kRightsIdSize);
|
memcpy(body->rights_id, mRightsId, ticket::kRightsIdSize);
|
||||||
body->account_id = (mAccountId);
|
body->account_id = (mAccountId);
|
||||||
body->sect_total_size = (mSectTotalSize);
|
body->sect_total_size = (mSectTotalSize);
|
||||||
body->sect_header_offset = (mSectHeaderOffset);
|
body->sect_header_offset = (mSectHeaderOffset);
|
||||||
|
@ -112,14 +112,17 @@ void es::TicketBody_V2::fromBytes(const byte_t * bytes, size_t len)
|
||||||
throw fnd::Exception(kModuleName, "Unsupported format version");
|
throw fnd::Exception(kModuleName, "Unsupported format version");
|
||||||
}
|
}
|
||||||
|
|
||||||
mIssuer.append(body->issuer, ticket::kIssuerSize);
|
mIssuer = std::string(body->issuer, _MIN(strlen(body->issuer), ticket::kIssuerSize));
|
||||||
memcpy(mEncTitleKey, body->enc_title_key, ticket::kEncTitleKeySize);
|
memcpy(mEncTitleKey, body->enc_title_key, ticket::kEncTitleKeySize);
|
||||||
mEncType = (ticket::TitleKeyEncType)body->title_key_enc_type;
|
mEncType = (ticket::TitleKeyEncType)body->title_key_enc_type;
|
||||||
mTicketVersion = body->ticket_version.get();
|
mTicketVersion = body->ticket_version.get();
|
||||||
mLicenseType = (ticket::LicenseType)body->license_type;
|
mLicenseType = (ticket::LicenseType)body->license_type;
|
||||||
mPreInstall = _HAS_BIT(body->property_mask, ticket::FLAG_PRE_INSTALL);
|
mCommonKeyId = body->common_key_id;
|
||||||
mSharedTitle = _HAS_BIT(body->property_mask, ticket::FLAG_SHARED_TITLE);
|
for (size_t i = 0; i < mPropertyFlags.size(); i++)
|
||||||
mAllowAllContent = _HAS_BIT(body->property_mask, ticket::FLAG_ALLOW_ALL_CONTENT);
|
{
|
||||||
|
if (_HAS_BIT(body->property_mask, i))
|
||||||
|
mPropertyFlags.addElement((ticket::PropertyMaskFlags)i);
|
||||||
|
}
|
||||||
memcpy(mReservedRegion, body->reserved_region, ticket::kReservedRegionSize);
|
memcpy(mReservedRegion, body->reserved_region, ticket::kReservedRegionSize);
|
||||||
mTicketId = body->ticket_id.get();
|
mTicketId = body->ticket_id.get();
|
||||||
mDeviceId = body->device_id.get();
|
mDeviceId = body->device_id.get();
|
||||||
|
@ -144,9 +147,8 @@ void es::TicketBody_V2::clear()
|
||||||
mEncType = ticket::AES128_CBC;
|
mEncType = ticket::AES128_CBC;
|
||||||
mTicketVersion = 0;
|
mTicketVersion = 0;
|
||||||
mLicenseType = ticket::LICENSE_PERMANENT;
|
mLicenseType = ticket::LICENSE_PERMANENT;
|
||||||
mPreInstall = false;
|
mCommonKeyId = 0;
|
||||||
mSharedTitle = false;
|
mPropertyFlags.clear();
|
||||||
mAllowAllContent = false;
|
|
||||||
memset(mReservedRegion, 0, ticket::kReservedRegionSize);
|
memset(mReservedRegion, 0, ticket::kReservedRegionSize);
|
||||||
mTicketId = 0;
|
mTicketId = 0;
|
||||||
mDeviceId = 0;
|
mDeviceId = 0;
|
||||||
|
@ -224,34 +226,14 @@ void es::TicketBody_V2::setCommonKeyId(byte_t id)
|
||||||
mCommonKeyId = id;
|
mCommonKeyId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool es::TicketBody_V2::isPreInstall() const
|
const fnd::List<es::ticket::PropertyMaskFlags>& es::TicketBody_V2::getPropertyFlags() const
|
||||||
{
|
{
|
||||||
return mPreInstall;
|
return mPropertyFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::TicketBody_V2::setIsPreInstall(bool isPreInstall)
|
void es::TicketBody_V2::setPropertyFlags(const fnd::List<es::ticket::PropertyMaskFlags>& flags)
|
||||||
{
|
{
|
||||||
mPreInstall = isPreInstall;
|
mPropertyFlags = flags;
|
||||||
}
|
|
||||||
|
|
||||||
bool es::TicketBody_V2::isSharedTitle() const
|
|
||||||
{
|
|
||||||
return mSharedTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void es::TicketBody_V2::setIsSharedTitle(bool isSharedTitle)
|
|
||||||
{
|
|
||||||
mSharedTitle = isSharedTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool es::TicketBody_V2::allowAllContent() const
|
|
||||||
{
|
|
||||||
return mAllowAllContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void es::TicketBody_V2::setAllowAllContent(bool allowAllContent)
|
|
||||||
{
|
|
||||||
mAllowAllContent = allowAllContent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const byte_t * es::TicketBody_V2::getReservedRegion() const
|
const byte_t * es::TicketBody_V2::getReservedRegion() const
|
||||||
|
|
|
@ -146,6 +146,11 @@ namespace fnd
|
||||||
{
|
{
|
||||||
fnd::Exception("Vec", "Failed to allocate memory for vector");
|
fnd::Exception("Vec", "Failed to allocate memory for vector");
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < new_size; i++)
|
||||||
|
{
|
||||||
|
m_Vec[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
m_Size = new_size;
|
m_Size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +164,10 @@ namespace fnd
|
||||||
{
|
{
|
||||||
fnd::Exception("Vec", "Failed to allocate memory for vector");
|
fnd::Exception("Vec", "Failed to allocate memory for vector");
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < new_size; i++)
|
||||||
|
{
|
||||||
|
new_vec[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < _MIN(m_Size, new_size); i++)
|
for (size_t i = 0; i < _MIN(m_Size, new_size); i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/ISerialisable.h>
|
#include <fnd/ISerialisable.h>
|
||||||
#include <es/cert.h>
|
#include <pki/cert.h>
|
||||||
|
|
||||||
namespace es
|
namespace pki
|
||||||
{
|
{
|
||||||
class CertificateBody
|
class CertificateBody
|
||||||
: public fnd::ISerialisable
|
: public fnd::ISerialisable
|
||||||
|
@ -27,7 +27,7 @@ namespace es
|
||||||
const std::string& getIssuer() const;
|
const std::string& getIssuer() const;
|
||||||
void setIssuer(const std::string& issuer);
|
void setIssuer(const std::string& issuer);
|
||||||
|
|
||||||
es::cert::PublicKeyType getPublicKeyType() const;
|
pki::cert::PublicKeyType getPublicKeyType() const;
|
||||||
void setPublicKeyType(cert::PublicKeyType type);
|
void setPublicKeyType(cert::PublicKeyType type);
|
||||||
|
|
||||||
const std::string& getSubject() const;
|
const std::string& getSubject() const;
|
14
lib/libpki/include/pki/SignUtils.h
Normal file
14
lib/libpki/include/pki/SignUtils.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
#include <pki/sign.h>
|
||||||
|
#include <crypto/sha.h>
|
||||||
|
|
||||||
|
namespace pki
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace sign
|
||||||
|
{
|
||||||
|
pki::sign::SignatureAlgo getSignatureAlgo(pki::sign::SignatureId sign_id);
|
||||||
|
pki::sign::HashAlgo getHashAlgo(pki::sign::SignatureId sign_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/ISerialisable.h>
|
#include <fnd/ISerialisable.h>
|
||||||
#include <es/sign.h>
|
#include <pki/sign.h>
|
||||||
|
|
||||||
namespace es
|
namespace pki
|
||||||
{
|
{
|
||||||
class SignatureBlock
|
class SignatureBlock
|
||||||
: public fnd::ISerialisable
|
: public fnd::ISerialisable
|
||||||
|
@ -24,8 +24,8 @@ namespace es
|
||||||
// variables
|
// variables
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
es::sign::SignType getSignType() const;
|
pki::sign::SignatureId getSignType() const;
|
||||||
void setSignType(es::sign::SignType type);
|
void setSignType(pki::sign::SignatureId type);
|
||||||
|
|
||||||
bool isLittleEndian() const;
|
bool isLittleEndian() const;
|
||||||
void setLittleEndian(bool isLE);
|
void setLittleEndian(bool isLE);
|
||||||
|
@ -41,7 +41,7 @@ namespace es
|
||||||
fnd::Vec<byte_t> mRawBinary;
|
fnd::Vec<byte_t> mRawBinary;
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
es::sign::SignType mSignType;
|
pki::sign::SignatureId mSignType;
|
||||||
bool mIsLittleEndian;
|
bool mIsLittleEndian;
|
||||||
fnd::Vec<byte_t> mSignature;
|
fnd::Vec<byte_t> mSignature;
|
||||||
};
|
};
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/ISerialisable.h>
|
#include <fnd/ISerialisable.h>
|
||||||
#include <es/SignatureBlock.h>
|
#include <pki/SignatureBlock.h>
|
||||||
|
|
||||||
namespace es
|
namespace pki
|
||||||
{
|
{
|
||||||
template <class T>
|
template <class T>
|
||||||
class SignedData
|
class SignedData
|
||||||
|
@ -25,7 +25,7 @@ namespace es
|
||||||
// variables
|
// variables
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
const es::SignatureBlock& getSignature() const;
|
const pki::SignatureBlock& getSignature() const;
|
||||||
void setSignature(const SignatureBlock& signature);
|
void setSignature(const SignatureBlock& signature);
|
||||||
|
|
||||||
const T& getBody() const;
|
const T& getBody() const;
|
||||||
|
@ -111,7 +111,7 @@ namespace es
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline const es::SignatureBlock& SignedData<T>::getSignature() const
|
inline const pki::SignatureBlock& SignedData<T>::getSignature() const
|
||||||
{
|
{
|
||||||
return mSignature;
|
return mSignature;
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
#include <crypto/rsa.h>
|
#include <crypto/rsa.h>
|
||||||
#include <crypto/ecdsa.h>
|
#include <crypto/ecdsa.h>
|
||||||
|
|
||||||
namespace es
|
namespace pki
|
||||||
{
|
{
|
||||||
namespace cert
|
namespace cert
|
||||||
{
|
{
|
|
@ -5,21 +5,37 @@
|
||||||
#include <crypto/rsa.h>
|
#include <crypto/rsa.h>
|
||||||
#include <crypto/ecdsa.h>
|
#include <crypto/ecdsa.h>
|
||||||
|
|
||||||
namespace es
|
namespace pki
|
||||||
{
|
{
|
||||||
namespace sign
|
namespace sign
|
||||||
{
|
{
|
||||||
enum SignType
|
enum SignatureId
|
||||||
{
|
{
|
||||||
SIGN_RSA4096_SHA1 = 0x10000,
|
SIGN_ID_RSA4096_SHA1 = 0x10000,
|
||||||
SIGN_RSA2048_SHA1,
|
SIGN_ID_RSA2048_SHA1,
|
||||||
SIGN_ECDSA240_SHA1,
|
SIGN_ID_ECDSA240_SHA1,
|
||||||
SIGN_RSA4096_SHA256,
|
SIGN_ID_RSA4096_SHA256,
|
||||||
SIGN_RSA2048_SHA256,
|
SIGN_ID_RSA2048_SHA256,
|
||||||
SIGN_ECDSA240_SHA256,
|
SIGN_ID_ECDSA240_SHA256,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SignatureAlgo
|
||||||
|
{
|
||||||
|
SIGN_ALGO_RSA4096,
|
||||||
|
SIGN_ALGO_RSA2048,
|
||||||
|
SIGN_ALGO_ECDSA240
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HashAlgo
|
||||||
|
{
|
||||||
|
HASH_ALGO_SHA1,
|
||||||
|
HASH_ALGO_SHA256
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t kEcdsaSigSize = 0x3C;
|
static const size_t kEcdsaSigSize = 0x3C;
|
||||||
|
|
||||||
|
static const std::string kRootIssuerStr = "Root";
|
||||||
|
static const std::string kIdentDelimiter = "-";
|
||||||
}
|
}
|
||||||
#pragma pack(push,1)
|
#pragma pack(push,1)
|
||||||
struct sRsa4096SignBlock
|
struct sRsa4096SignBlock
|
144
lib/libpki/libpki.vcxproj
Normal file
144
lib/libpki/libpki.vcxproj
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{B9113734-6E84-44FF-8CF7-58199AA815C5}</ProjectGuid>
|
||||||
|
<RootNamespace>libpki</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<AdditionalIncludeDirectories>..\libfnd\include;..\libcrypto\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<AdditionalIncludeDirectories>..\libfnd\include;..\libcrypto\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<AdditionalIncludeDirectories>..\libfnd\include;..\libcrypto\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<AdditionalIncludeDirectories>..\libfnd\include;..\libcrypto\include;..\libpki\include;</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="include\pki\cert.h" />
|
||||||
|
<ClInclude Include="include\pki\CertificateBody.h" />
|
||||||
|
<ClInclude Include="include\pki\sign.h" />
|
||||||
|
<ClInclude Include="include\pki\SignatureBlock.h" />
|
||||||
|
<ClInclude Include="include\pki\SignedData.h" />
|
||||||
|
<ClInclude Include="include\pki\SignUtils.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="source\CertificateBody.cpp" />
|
||||||
|
<ClCompile Include="source\SignatureBlock.cpp" />
|
||||||
|
<ClCompile Include="source\SignUtils.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="makefile" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
51
lib/libpki/libpki.vcxproj.filters
Normal file
51
lib/libpki/libpki.vcxproj.filters
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="include\pki\cert.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\pki\CertificateBody.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\pki\sign.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\pki\SignatureBlock.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\pki\SignedData.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\pki\SignUtils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="source\CertificateBody.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\SignatureBlock.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\SignUtils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="makefile" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
4
lib/libpki/libpki.vcxproj.user
Normal file
4
lib/libpki/libpki.vcxproj.user
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup />
|
||||||
|
</Project>
|
47
lib/libpki/makefile
Normal file
47
lib/libpki/makefile
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Sources
|
||||||
|
SRC_DIR = source
|
||||||
|
OBJS = $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c)))
|
||||||
|
|
||||||
|
# External dependencies
|
||||||
|
DEPENDS = fnd crypto
|
||||||
|
LIB_DIR = ..
|
||||||
|
INCS = -I"include" $(foreach dep,$(DEPENDS), -I"$(LIB_DIR)/lib$(dep)/include")
|
||||||
|
|
||||||
|
|
||||||
|
# Compiler Settings
|
||||||
|
CXXFLAGS = -std=c++11 $(INCS) -D__STDC_FORMAT_MACROS -Wall -Wno-unused-value
|
||||||
|
CFLAGS = -std=c11 $(INCS) -Wall -Wno-unused-value
|
||||||
|
ARFLAGS = cr -o
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
# Windows Only Flags/Libs
|
||||||
|
CC = x86_64-w64-mingw32-gcc
|
||||||
|
CXX = x86_64-w64-mingw32-g++
|
||||||
|
CFLAGS += -Wno-unused-but-set-variable
|
||||||
|
CXXFLAGS += -Wno-unused-but-set-variable
|
||||||
|
else
|
||||||
|
UNAME = $(shell uname -s)
|
||||||
|
ifeq ($(UNAME), Darwin)
|
||||||
|
# MacOS Only Flags/Libs
|
||||||
|
CFLAGS += -Wno-unused-private-field
|
||||||
|
CXXFLAGS += -Wno-unused-private-field
|
||||||
|
ARFLAGS = rc
|
||||||
|
else
|
||||||
|
# *nix Only Flags/Libs
|
||||||
|
CFLAGS += -Wno-unused-but-set-variable
|
||||||
|
CXXFLAGS += -Wno-unused-but-set-variable
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Output
|
||||||
|
OUTPUT = $(shell basename $(CURDIR)).a
|
||||||
|
|
||||||
|
main: build
|
||||||
|
|
||||||
|
rebuild: clean build
|
||||||
|
|
||||||
|
build: $(OBJS)
|
||||||
|
ar $(ARFLAGS) $(OUTPUT) $(OBJS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OUTPUT) $(OBJS)
|
|
@ -1,16 +1,16 @@
|
||||||
#include <es/CertificateBody.h>
|
#include <pki/CertificateBody.h>
|
||||||
|
|
||||||
es::CertificateBody::CertificateBody()
|
pki::CertificateBody::CertificateBody()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
es::CertificateBody::CertificateBody(const CertificateBody& other)
|
pki::CertificateBody::CertificateBody(const CertificateBody& other)
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::operator=(const CertificateBody& other)
|
void pki::CertificateBody::operator=(const CertificateBody& other)
|
||||||
{
|
{
|
||||||
mRawBinary = other.mRawBinary;
|
mRawBinary = other.mRawBinary;
|
||||||
mIssuer = other.mIssuer;
|
mIssuer = other.mIssuer;
|
||||||
|
@ -22,7 +22,7 @@ void es::CertificateBody::operator=(const CertificateBody& other)
|
||||||
mEcdsa240PublicKey = other.mEcdsa240PublicKey;
|
mEcdsa240PublicKey = other.mEcdsa240PublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool es::CertificateBody::operator==(const CertificateBody& other) const
|
bool pki::CertificateBody::operator==(const CertificateBody& other) const
|
||||||
{
|
{
|
||||||
return (mIssuer == other.mIssuer) \
|
return (mIssuer == other.mIssuer) \
|
||||||
&& (mSubject == other.mSubject) \
|
&& (mSubject == other.mSubject) \
|
||||||
|
@ -33,12 +33,12 @@ bool es::CertificateBody::operator==(const CertificateBody& other) const
|
||||||
&& (mEcdsa240PublicKey == other.mEcdsa240PublicKey);
|
&& (mEcdsa240PublicKey == other.mEcdsa240PublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool es::CertificateBody::operator!=(const CertificateBody& other) const
|
bool pki::CertificateBody::operator!=(const CertificateBody& other) const
|
||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::toBytes()
|
void pki::CertificateBody::toBytes()
|
||||||
{
|
{
|
||||||
// get public key size
|
// get public key size
|
||||||
size_t pubkeySize = 0;
|
size_t pubkeySize = 0;
|
||||||
|
@ -86,7 +86,7 @@ void es::CertificateBody::toBytes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::fromBytes(const byte_t* src, size_t size)
|
void pki::CertificateBody::fromBytes(const byte_t* src, size_t size)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
@ -129,10 +129,10 @@ void es::CertificateBody::fromBytes(const byte_t* src, size_t size)
|
||||||
hdr = (const sCertificateHeader*)mRawBinary.data();
|
hdr = (const sCertificateHeader*)mRawBinary.data();
|
||||||
|
|
||||||
if (hdr->issuer[0] != 0)
|
if (hdr->issuer[0] != 0)
|
||||||
mIssuer = std::string(hdr->issuer, cert::kIssuerSize);
|
mIssuer = std::string(hdr->issuer, _MIN(strlen(hdr->issuer), cert::kIssuerSize));
|
||||||
mPublicKeyType = (cert::PublicKeyType)hdr->key_type.get();
|
mPublicKeyType = (cert::PublicKeyType)hdr->key_type.get();
|
||||||
if (hdr->subject[0] != 0)
|
if (hdr->subject[0] != 0)
|
||||||
mSubject = std::string(hdr->subject, cert::kSubjectSize);
|
mSubject = std::string(hdr->subject, _MIN(strlen(hdr->subject), cert::kSubjectSize));
|
||||||
mCertId = hdr->cert_id.get();
|
mCertId = hdr->cert_id.get();
|
||||||
|
|
||||||
// save public key
|
// save public key
|
||||||
|
@ -155,13 +155,13 @@ void es::CertificateBody::fromBytes(const byte_t* src, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fnd::Vec<byte_t>& es::CertificateBody::getBytes() const
|
const fnd::Vec<byte_t>& pki::CertificateBody::getBytes() const
|
||||||
{
|
{
|
||||||
return mRawBinary;
|
return mRawBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void es::CertificateBody::clear()
|
void pki::CertificateBody::clear()
|
||||||
{
|
{
|
||||||
mIssuer.clear();
|
mIssuer.clear();
|
||||||
mSubject.clear();
|
mSubject.clear();
|
||||||
|
@ -173,12 +173,12 @@ void es::CertificateBody::clear()
|
||||||
memset(&mEcdsa240PublicKey, 0, sizeof(crypto::ecdsa::sEcdsa240Point));
|
memset(&mEcdsa240PublicKey, 0, sizeof(crypto::ecdsa::sEcdsa240Point));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& es::CertificateBody::getIssuer() const
|
const std::string& pki::CertificateBody::getIssuer() const
|
||||||
{
|
{
|
||||||
return mIssuer;
|
return mIssuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setIssuer(const std::string& issuer)
|
void pki::CertificateBody::setIssuer(const std::string& issuer)
|
||||||
{
|
{
|
||||||
if (issuer.size() > cert::kIssuerSize)
|
if (issuer.size() > cert::kIssuerSize)
|
||||||
{
|
{
|
||||||
|
@ -188,22 +188,22 @@ void es::CertificateBody::setIssuer(const std::string& issuer)
|
||||||
mIssuer = issuer;
|
mIssuer = issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
es::cert::PublicKeyType es::CertificateBody::getPublicKeyType() const
|
pki::cert::PublicKeyType pki::CertificateBody::getPublicKeyType() const
|
||||||
{
|
{
|
||||||
return mPublicKeyType;
|
return mPublicKeyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setPublicKeyType(cert::PublicKeyType type)
|
void pki::CertificateBody::setPublicKeyType(cert::PublicKeyType type)
|
||||||
{
|
{
|
||||||
mPublicKeyType = type;
|
mPublicKeyType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& es::CertificateBody::getSubject() const
|
const std::string& pki::CertificateBody::getSubject() const
|
||||||
{
|
{
|
||||||
return mSubject;
|
return mSubject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setSubject(const std::string& subject)
|
void pki::CertificateBody::setSubject(const std::string& subject)
|
||||||
{
|
{
|
||||||
if (subject.size() > cert::kSubjectSize)
|
if (subject.size() > cert::kSubjectSize)
|
||||||
{
|
{
|
||||||
|
@ -213,42 +213,42 @@ void es::CertificateBody::setSubject(const std::string& subject)
|
||||||
mSubject = subject;
|
mSubject = subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t es::CertificateBody::getCertId() const
|
uint32_t pki::CertificateBody::getCertId() const
|
||||||
{
|
{
|
||||||
return mCertId;
|
return mCertId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setCertId(uint32_t id)
|
void pki::CertificateBody::setCertId(uint32_t id)
|
||||||
{
|
{
|
||||||
mCertId = id;
|
mCertId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const crypto::rsa::sRsa4096Key& es::CertificateBody::getRsa4098PublicKey() const
|
const crypto::rsa::sRsa4096Key& pki::CertificateBody::getRsa4098PublicKey() const
|
||||||
{
|
{
|
||||||
return mRsa4096PublicKey;
|
return mRsa4096PublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setRsa4098PublicKey(const crypto::rsa::sRsa4096Key& key)
|
void pki::CertificateBody::setRsa4098PublicKey(const crypto::rsa::sRsa4096Key& key)
|
||||||
{
|
{
|
||||||
mRsa4096PublicKey = key;
|
mRsa4096PublicKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
const crypto::rsa::sRsa2048Key& es::CertificateBody::getRsa2048PublicKey() const
|
const crypto::rsa::sRsa2048Key& pki::CertificateBody::getRsa2048PublicKey() const
|
||||||
{
|
{
|
||||||
return mRsa2048PublicKey;
|
return mRsa2048PublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setRsa2048PublicKey(const crypto::rsa::sRsa2048Key& key)
|
void pki::CertificateBody::setRsa2048PublicKey(const crypto::rsa::sRsa2048Key& key)
|
||||||
{
|
{
|
||||||
mRsa2048PublicKey = key;
|
mRsa2048PublicKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
const crypto::ecdsa::sEcdsa240Point& es::CertificateBody::getEcdsa240PublicKey() const
|
const crypto::ecdsa::sEcdsa240Point& pki::CertificateBody::getEcdsa240PublicKey() const
|
||||||
{
|
{
|
||||||
return mEcdsa240PublicKey;
|
return mEcdsa240PublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::CertificateBody::setEcdsa240PublicKey(const crypto::ecdsa::sEcdsa240Point& key)
|
void pki::CertificateBody::setEcdsa240PublicKey(const crypto::ecdsa::sEcdsa240Point& key)
|
||||||
{
|
{
|
||||||
mEcdsa240PublicKey = key;
|
mEcdsa240PublicKey = key;
|
||||||
}
|
}
|
45
lib/libpki/source/SignUtils.cpp
Normal file
45
lib/libpki/source/SignUtils.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include <pki/SignUtils.h>
|
||||||
|
|
||||||
|
pki::sign::SignatureAlgo pki::sign::getSignatureAlgo(pki::sign::SignatureId sign_id)
|
||||||
|
{
|
||||||
|
SignatureAlgo sign_algo = SIGN_ALGO_RSA4096;
|
||||||
|
|
||||||
|
switch (sign_id)
|
||||||
|
{
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA1):
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA256):
|
||||||
|
sign_algo = SIGN_ALGO_RSA4096;
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA1):
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA256):
|
||||||
|
sign_algo = SIGN_ALGO_RSA2048;
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
|
sign_algo = SIGN_ALGO_ECDSA240;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return sign_algo;
|
||||||
|
}
|
||||||
|
|
||||||
|
pki::sign::HashAlgo pki::sign::getHashAlgo(pki::sign::SignatureId sign_id)
|
||||||
|
{
|
||||||
|
HashAlgo hash_algo = HASH_ALGO_SHA1;
|
||||||
|
|
||||||
|
switch (sign_id)
|
||||||
|
{
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA1):
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA1):
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
|
hash_algo = HASH_ALGO_SHA1;
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA256):
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA256):
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
|
hash_algo = HASH_ALGO_SHA256;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return hash_algo;
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
#include <es/SignatureBlock.h>
|
#include <pki/SignatureBlock.h>
|
||||||
|
|
||||||
es::SignatureBlock::SignatureBlock()
|
pki::SignatureBlock::SignatureBlock()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
es::SignatureBlock::SignatureBlock(const SignatureBlock& other)
|
pki::SignatureBlock::SignatureBlock(const SignatureBlock& other)
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::operator=(const SignatureBlock& other)
|
void pki::SignatureBlock::operator=(const SignatureBlock& other)
|
||||||
{
|
{
|
||||||
mRawBinary = other.mRawBinary;
|
mRawBinary = other.mRawBinary;
|
||||||
mSignType = other.mSignType;
|
mSignType = other.mSignType;
|
||||||
|
@ -18,37 +18,37 @@ void es::SignatureBlock::operator=(const SignatureBlock& other)
|
||||||
mSignature = other.mSignature;
|
mSignature = other.mSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool es::SignatureBlock::operator==(const SignatureBlock& other) const
|
bool pki::SignatureBlock::operator==(const SignatureBlock& other) const
|
||||||
{
|
{
|
||||||
return (mSignType == other.mSignType) \
|
return (mSignType == other.mSignType) \
|
||||||
&& (mIsLittleEndian == other.mIsLittleEndian) \
|
&& (mIsLittleEndian == other.mIsLittleEndian) \
|
||||||
&& (mSignature == other.mSignature);
|
&& (mSignature == other.mSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool es::SignatureBlock::operator!=(const SignatureBlock& other) const
|
bool pki::SignatureBlock::operator!=(const SignatureBlock& other) const
|
||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::toBytes()
|
void pki::SignatureBlock::toBytes()
|
||||||
{
|
{
|
||||||
size_t totalSize = 0;
|
size_t totalSize = 0;
|
||||||
size_t sigSize = 0;
|
size_t sigSize = 0;
|
||||||
|
|
||||||
switch (mSignType)
|
switch (mSignType)
|
||||||
{
|
{
|
||||||
case (sign::SIGN_RSA4096_SHA1):
|
case (sign::SIGN_ID_RSA4096_SHA1):
|
||||||
case (sign::SIGN_RSA4096_SHA256):
|
case (sign::SIGN_ID_RSA4096_SHA256):
|
||||||
totalSize = sizeof(sRsa4096SignBlock);
|
totalSize = sizeof(sRsa4096SignBlock);
|
||||||
sigSize = crypto::rsa::kRsa4096Size;
|
sigSize = crypto::rsa::kRsa4096Size;
|
||||||
break;
|
break;
|
||||||
case (sign::SIGN_RSA2048_SHA1):
|
case (sign::SIGN_ID_RSA2048_SHA1):
|
||||||
case (sign::SIGN_RSA2048_SHA256):
|
case (sign::SIGN_ID_RSA2048_SHA256):
|
||||||
totalSize = sizeof(sRsa2048SignBlock);
|
totalSize = sizeof(sRsa2048SignBlock);
|
||||||
sigSize = crypto::rsa::kRsa2048Size;
|
sigSize = crypto::rsa::kRsa2048Size;
|
||||||
break;
|
break;
|
||||||
case (sign::SIGN_ECDSA240_SHA1):
|
case (sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
case (sign::SIGN_ECDSA240_SHA256):
|
case (sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
totalSize = sizeof(sEcdsa240SignBlock);
|
totalSize = sizeof(sEcdsa240SignBlock);
|
||||||
sigSize = sign::kEcdsaSigSize;
|
sigSize = sign::kEcdsaSigSize;
|
||||||
break;
|
break;
|
||||||
|
@ -68,7 +68,7 @@ void es::SignatureBlock::toBytes()
|
||||||
memcpy(mRawBinary.data() + 4, mSignature.data(), sigSize);
|
memcpy(mRawBinary.data() + 4, mSignature.data(), sigSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
|
void pki::SignatureBlock::fromBytes(const byte_t* src, size_t size)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
@ -80,18 +80,18 @@ void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
|
||||||
signType = ((be_uint32_t*)src)->get();
|
signType = ((be_uint32_t*)src)->get();
|
||||||
switch (signType)
|
switch (signType)
|
||||||
{
|
{
|
||||||
case (sign::SIGN_RSA4096_SHA1):
|
case (sign::SIGN_ID_RSA4096_SHA1):
|
||||||
case (sign::SIGN_RSA4096_SHA256):
|
case (sign::SIGN_ID_RSA4096_SHA256):
|
||||||
totalSize = sizeof(sRsa4096SignBlock);
|
totalSize = sizeof(sRsa4096SignBlock);
|
||||||
sigSize = crypto::rsa::kRsa4096Size;
|
sigSize = crypto::rsa::kRsa4096Size;
|
||||||
break;
|
break;
|
||||||
case (sign::SIGN_RSA2048_SHA1):
|
case (sign::SIGN_ID_RSA2048_SHA1):
|
||||||
case (sign::SIGN_RSA2048_SHA256):
|
case (sign::SIGN_ID_RSA2048_SHA256):
|
||||||
totalSize = sizeof(sRsa2048SignBlock);
|
totalSize = sizeof(sRsa2048SignBlock);
|
||||||
sigSize = crypto::rsa::kRsa2048Size;
|
sigSize = crypto::rsa::kRsa2048Size;
|
||||||
break;
|
break;
|
||||||
case (sign::SIGN_ECDSA240_SHA1):
|
case (sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
case (sign::SIGN_ECDSA240_SHA256):
|
case (sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
totalSize = sizeof(sEcdsa240SignBlock);
|
totalSize = sizeof(sEcdsa240SignBlock);
|
||||||
sigSize = sign::kEcdsaSigSize;
|
sigSize = sign::kEcdsaSigSize;
|
||||||
break;
|
break;
|
||||||
|
@ -103,18 +103,18 @@ void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
|
||||||
signType = ((le_uint32_t*)src)->get();
|
signType = ((le_uint32_t*)src)->get();
|
||||||
switch (signType)
|
switch (signType)
|
||||||
{
|
{
|
||||||
case (sign::SIGN_RSA4096_SHA1):
|
case (sign::SIGN_ID_RSA4096_SHA1):
|
||||||
case (sign::SIGN_RSA4096_SHA256):
|
case (sign::SIGN_ID_RSA4096_SHA256):
|
||||||
totalSize = sizeof(sRsa4096SignBlock);
|
totalSize = sizeof(sRsa4096SignBlock);
|
||||||
sigSize = crypto::rsa::kRsa4096Size;
|
sigSize = crypto::rsa::kRsa4096Size;
|
||||||
break;
|
break;
|
||||||
case (sign::SIGN_RSA2048_SHA1):
|
case (sign::SIGN_ID_RSA2048_SHA1):
|
||||||
case (sign::SIGN_RSA2048_SHA256):
|
case (sign::SIGN_ID_RSA2048_SHA256):
|
||||||
totalSize = sizeof(sRsa2048SignBlock);
|
totalSize = sizeof(sRsa2048SignBlock);
|
||||||
sigSize = crypto::rsa::kRsa2048Size;
|
sigSize = crypto::rsa::kRsa2048Size;
|
||||||
break;
|
break;
|
||||||
case (sign::SIGN_ECDSA240_SHA1):
|
case (sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
case (sign::SIGN_ECDSA240_SHA256):
|
case (sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
totalSize = sizeof(sEcdsa240SignBlock);
|
totalSize = sizeof(sEcdsa240SignBlock);
|
||||||
sigSize = sign::kEcdsaSigSize;
|
sigSize = sign::kEcdsaSigSize;
|
||||||
break;
|
break;
|
||||||
|
@ -133,50 +133,50 @@ void es::SignatureBlock::fromBytes(const byte_t* src, size_t size)
|
||||||
mRawBinary.alloc(totalSize);
|
mRawBinary.alloc(totalSize);
|
||||||
memcpy(mRawBinary.data(), src, totalSize);
|
memcpy(mRawBinary.data(), src, totalSize);
|
||||||
|
|
||||||
mSignType = (sign::SignType)signType;
|
mSignType = (sign::SignatureId)signType;
|
||||||
mSignature.alloc(sigSize);
|
mSignature.alloc(sigSize);
|
||||||
memcpy(mSignature.data(), mRawBinary.data() + 4, sigSize);
|
memcpy(mSignature.data(), mRawBinary.data() + 4, sigSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fnd::Vec<byte_t>& es::SignatureBlock::getBytes() const
|
const fnd::Vec<byte_t>& pki::SignatureBlock::getBytes() const
|
||||||
{
|
{
|
||||||
return mRawBinary;
|
return mRawBinary;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::clear()
|
void pki::SignatureBlock::clear()
|
||||||
{
|
{
|
||||||
mRawBinary.clear();
|
mRawBinary.clear();
|
||||||
mSignType = sign::SIGN_RSA4096_SHA1;
|
mSignType = sign::SIGN_ID_RSA4096_SHA1;
|
||||||
mIsLittleEndian = false;
|
mIsLittleEndian = false;
|
||||||
mSignature.clear();
|
mSignature.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
es::sign::SignType es::SignatureBlock::getSignType() const
|
pki::sign::SignatureId pki::SignatureBlock::getSignType() const
|
||||||
{
|
{
|
||||||
return mSignType;
|
return mSignType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::setSignType(es::sign::SignType type)
|
void pki::SignatureBlock::setSignType(pki::sign::SignatureId type)
|
||||||
{
|
{
|
||||||
mSignType = type;
|
mSignType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool es::SignatureBlock::isLittleEndian() const
|
bool pki::SignatureBlock::isLittleEndian() const
|
||||||
{
|
{
|
||||||
return mIsLittleEndian;
|
return mIsLittleEndian;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::setLittleEndian(bool isLE)
|
void pki::SignatureBlock::setLittleEndian(bool isLE)
|
||||||
{
|
{
|
||||||
mIsLittleEndian = isLE;
|
mIsLittleEndian = isLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fnd::Vec<byte_t>& es::SignatureBlock::getSignature() const
|
const fnd::Vec<byte_t>& pki::SignatureBlock::getSignature() const
|
||||||
{
|
{
|
||||||
return mSignature;
|
return mSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
void es::SignatureBlock::setSignature(const fnd::Vec<byte_t>& signature)
|
void pki::SignatureBlock::setSignature(const fnd::Vec<byte_t>& signature)
|
||||||
{
|
{
|
||||||
mSignature = signature;
|
mSignature = signature;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
LIBS = libfnd libcrypto libcompress libes libnx libnx-hb
|
LIBS = libfnd libcrypto libcompress libes libpki libnx libnx-hb
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
rebuild: clean build
|
rebuild: clean build
|
||||||
|
|
|
@ -3,7 +3,7 @@ SRC_DIR = source
|
||||||
OBJS = $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c)))
|
OBJS = $(foreach dir,$(SRC_DIR),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(SRC_DIR),$(subst .c,.o,$(wildcard $(dir)/*.c)))
|
||||||
|
|
||||||
# External dependencies
|
# External dependencies
|
||||||
DEPENDS = nx-hb nx crypto compress fnd
|
DEPENDS = nx-hb nx es pki crypto compress fnd
|
||||||
LIB_DIR = ../../lib
|
LIB_DIR = ../../lib
|
||||||
LIBS = $(foreach dep,$(DEPENDS), -L"$(LIB_DIR)/lib$(dep)" -l$(dep))
|
LIBS = $(foreach dep,$(DEPENDS), -L"$(LIB_DIR)/lib$(dep)" -l$(dep))
|
||||||
INCS = $(foreach dep,$(DEPENDS), -I"$(LIB_DIR)/lib$(dep)/include")
|
INCS = $(foreach dep,$(DEPENDS), -I"$(LIB_DIR)/lib$(dep)/include")
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<AdditionalIncludeDirectories>..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\..\lib\libpki\include;..\..\lib\libes\include;..\..\lib\libfnd\include;..\..\lib\libcompress\include;..\..\lib\libcrypto\include;..\..\lib\libnx\include;..\..\lib\libnx-hb\include</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
@ -157,6 +157,9 @@
|
||||||
<ProjectReference Include="..\..\lib\libcrypto\crypto.vcxproj">
|
<ProjectReference Include="..\..\lib\libcrypto\crypto.vcxproj">
|
||||||
<Project>{6adbb60d-dba0-411d-bd2d-a355ef8e0fe1}</Project>
|
<Project>{6adbb60d-dba0-411d-bd2d-a355ef8e0fe1}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\lib\libes\es.vcxproj">
|
||||||
|
<Project>{7be99936-0d40-410d-944b-4513c2eff8dc}</Project>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\lib\libfnd\fnd.vcxproj">
|
<ProjectReference Include="..\..\lib\libfnd\fnd.vcxproj">
|
||||||
<Project>{4d27edb9-5110-44fe-8ce2-d46c5ad3c55b}</Project>
|
<Project>{4d27edb9-5110-44fe-8ce2-d46c5ad3c55b}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
@ -166,12 +169,19 @@
|
||||||
<ProjectReference Include="..\..\lib\libnx\nx.vcxproj">
|
<ProjectReference Include="..\..\lib\libnx\nx.vcxproj">
|
||||||
<Project>{91ba9e79-8242-4f7d-b997-0dfec95ea22b}</Project>
|
<Project>{91ba9e79-8242-4f7d-b997-0dfec95ea22b}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\lib\libpki\libpki.vcxproj">
|
||||||
|
<Project>{b9113734-6e84-44ff-8cf7-58199aa815c5}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="makefile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
||||||
<ClInclude Include="source\AssetProcess.h" />
|
<ClInclude Include="source\AssetProcess.h" />
|
||||||
<ClInclude Include="source\CnmtProcess.h" />
|
<ClInclude Include="source\CnmtProcess.h" />
|
||||||
<ClInclude Include="source\ElfSymbolParser.h" />
|
<ClInclude Include="source\ElfSymbolParser.h" />
|
||||||
|
<ClInclude Include="source\EsTikProcess.h" />
|
||||||
<ClInclude Include="source\HashTreeMeta.h" />
|
<ClInclude Include="source\HashTreeMeta.h" />
|
||||||
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
||||||
<ClInclude Include="source\NacpProcess.h" />
|
<ClInclude Include="source\NacpProcess.h" />
|
||||||
|
@ -182,6 +192,8 @@
|
||||||
<ClInclude Include="source\nstool.h" />
|
<ClInclude Include="source\nstool.h" />
|
||||||
<ClInclude Include="source\OffsetAdjustedIFile.h" />
|
<ClInclude Include="source\OffsetAdjustedIFile.h" />
|
||||||
<ClInclude Include="source\PfsProcess.h" />
|
<ClInclude Include="source\PfsProcess.h" />
|
||||||
|
<ClInclude Include="source\PkiCertProcess.h" />
|
||||||
|
<ClInclude Include="source\PkiValidator.h" />
|
||||||
<ClInclude Include="source\RoMetadataProcess.h" />
|
<ClInclude Include="source\RoMetadataProcess.h" />
|
||||||
<ClInclude Include="source\RomfsProcess.h" />
|
<ClInclude Include="source\RomfsProcess.h" />
|
||||||
<ClInclude Include="source\SdkApiString.h" />
|
<ClInclude Include="source\SdkApiString.h" />
|
||||||
|
@ -194,6 +206,7 @@
|
||||||
<ClCompile Include="source\AssetProcess.cpp" />
|
<ClCompile Include="source\AssetProcess.cpp" />
|
||||||
<ClCompile Include="source\CnmtProcess.cpp" />
|
<ClCompile Include="source\CnmtProcess.cpp" />
|
||||||
<ClCompile Include="source\ElfSymbolParser.cpp" />
|
<ClCompile Include="source\ElfSymbolParser.cpp" />
|
||||||
|
<ClCompile Include="source\EsTikProcess.cpp" />
|
||||||
<ClCompile Include="source\HashTreeMeta.cpp" />
|
<ClCompile Include="source\HashTreeMeta.cpp" />
|
||||||
<ClCompile Include="source\HashTreeWrappedIFile.cpp" />
|
<ClCompile Include="source\HashTreeWrappedIFile.cpp" />
|
||||||
<ClCompile Include="source\main.cpp" />
|
<ClCompile Include="source\main.cpp" />
|
||||||
|
@ -204,15 +217,14 @@
|
||||||
<ClCompile Include="source\NsoProcess.cpp" />
|
<ClCompile Include="source\NsoProcess.cpp" />
|
||||||
<ClCompile Include="source\OffsetAdjustedIFile.cpp" />
|
<ClCompile Include="source\OffsetAdjustedIFile.cpp" />
|
||||||
<ClCompile Include="source\PfsProcess.cpp" />
|
<ClCompile Include="source\PfsProcess.cpp" />
|
||||||
|
<ClCompile Include="source\PkiCertProcess.cpp" />
|
||||||
|
<ClCompile Include="source\PkiValidator.cpp" />
|
||||||
<ClCompile Include="source\RoMetadataProcess.cpp" />
|
<ClCompile Include="source\RoMetadataProcess.cpp" />
|
||||||
<ClCompile Include="source\RomfsProcess.cpp" />
|
<ClCompile Include="source\RomfsProcess.cpp" />
|
||||||
<ClCompile Include="source\SdkApiString.cpp" />
|
<ClCompile Include="source\SdkApiString.cpp" />
|
||||||
<ClCompile Include="source\UserSettings.cpp" />
|
<ClCompile Include="source\UserSettings.cpp" />
|
||||||
<ClCompile Include="source\XciProcess.cpp" />
|
<ClCompile Include="source\XciProcess.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="makefile" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
|
|
@ -15,21 +15,69 @@
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="makefile" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="source\AesCtrWrappedIFile.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\AssetProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\CnmtProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\ElfSymbolParser.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\EsTikProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\HashTreeMeta.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\HashTreeWrappedIFile.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\NacpProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="source\NcaProcess.h">
|
<ClInclude Include="source\NcaProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\NpdmProcess.h">
|
<ClInclude Include="source\NpdmProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\NroProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\NsoProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="source\nstool.h">
|
<ClInclude Include="source\nstool.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\OffsetAdjustedIFile.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="source\PfsProcess.h">
|
<ClInclude Include="source\PfsProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\PkiCertProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\PkiValidator.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\RoMetadataProcess.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="source\RomfsProcess.h">
|
<ClInclude Include="source\RomfsProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\SdkApiString.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="source\UserSettings.h">
|
<ClInclude Include="source\UserSettings.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -39,103 +87,73 @@
|
||||||
<ClInclude Include="source\XciProcess.h">
|
<ClInclude Include="source\XciProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\AesCtrWrappedIFile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\OffsetAdjustedIFile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\CnmtProcess.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\HashTreeMeta.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\HashTreeWrappedIFile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\NsoProcess.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\AssetProcess.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\NroProcess.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\SdkApiString.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\NacpProcess.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\ElfSymbolParser.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\RoMetadataProcess.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\main.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\NpdmProcess.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\PfsProcess.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\UserSettings.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\XciProcess.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\RomfsProcess.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\AesCtrWrappedIFile.cpp">
|
<ClCompile Include="source\AesCtrWrappedIFile.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\NcaProcess.cpp">
|
<ClCompile Include="source\AssetProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\OffsetAdjustedIFile.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\CnmtProcess.cpp">
|
<ClCompile Include="source\CnmtProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\ElfSymbolParser.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\EsTikProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="source\HashTreeMeta.cpp">
|
<ClCompile Include="source\HashTreeMeta.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\HashTreeWrappedIFile.cpp">
|
<ClCompile Include="source\HashTreeWrappedIFile.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\NsoProcess.cpp">
|
<ClCompile Include="source\main.cpp">
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\AssetProcess.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\NroProcess.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\SdkApiString.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\NacpProcess.cpp">
|
<ClCompile Include="source\NacpProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\ElfSymbolParser.cpp">
|
<ClCompile Include="source\NcaProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\NpdmProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\NroProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\NsoProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\OffsetAdjustedIFile.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\PfsProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\PkiCertProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\PkiValidator.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\RoMetadataProcess.cpp">
|
<ClCompile Include="source\RoMetadataProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
<ClCompile Include="source\RomfsProcess.cpp">
|
||||||
<ItemGroup>
|
<Filter>Source Files</Filter>
|
||||||
<None Include="makefile" />
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\SdkApiString.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\UserSettings.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\XciProcess.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
269
programs/nstool/source/EsTikProcess.cpp
Normal file
269
programs/nstool/source/EsTikProcess.cpp
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <pki/SignUtils.h>
|
||||||
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
#include "EsTikProcess.h"
|
||||||
|
#include "PkiValidator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EsTikProcess::EsTikProcess() :
|
||||||
|
mFile(nullptr),
|
||||||
|
mOwnIFile(false),
|
||||||
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
|
mVerify(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EsTikProcess::~EsTikProcess()
|
||||||
|
{
|
||||||
|
if (mOwnIFile)
|
||||||
|
{
|
||||||
|
delete mFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::process()
|
||||||
|
{
|
||||||
|
importTicket();
|
||||||
|
|
||||||
|
if (mVerify)
|
||||||
|
verifyTicket();
|
||||||
|
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
|
displayTicket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||||
|
{
|
||||||
|
mFile = file;
|
||||||
|
mOwnIFile = ownIFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::setKeyset(const sKeyset* keyset)
|
||||||
|
{
|
||||||
|
mKeyset = keyset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::setCertificateChain(const fnd::List<pki::SignedData<pki::CertificateBody>>& certs)
|
||||||
|
{
|
||||||
|
mCerts = certs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::setCliOutputMode(CliOutputMode mode)
|
||||||
|
{
|
||||||
|
mCliOutputMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::setVerifyMode(bool verify)
|
||||||
|
{
|
||||||
|
mVerify = verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::importTicket()
|
||||||
|
{
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fnd::Vec<byte_t> scratch;
|
||||||
|
scratch.alloc(mFile->size());
|
||||||
|
mFile->read(scratch.data(), 0, scratch.size());
|
||||||
|
mTik.fromBytes(scratch.data(), scratch.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::verifyTicket()
|
||||||
|
{
|
||||||
|
PkiValidator pki_validator;
|
||||||
|
fnd::Vec<byte_t> tik_hash;
|
||||||
|
|
||||||
|
switch (pki::sign::getHashAlgo(mTik.getSignature().getSignType()))
|
||||||
|
{
|
||||||
|
case (pki::sign::HASH_ALGO_SHA1):
|
||||||
|
tik_hash.alloc(crypto::sha::kSha1HashLen);
|
||||||
|
crypto::sha::Sha1(mTik.getBody().getBytes().data(), mTik.getBody().getBytes().size(), tik_hash.data());
|
||||||
|
break;
|
||||||
|
case (pki::sign::HASH_ALGO_SHA256):
|
||||||
|
tik_hash.alloc(crypto::sha::kSha256HashLen);
|
||||||
|
crypto::sha::Sha256(mTik.getBody().getBytes().data(), mTik.getBody().getBytes().size(), tik_hash.data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pki_validator.setRootKey(mKeyset->pki.root_sign_key);
|
||||||
|
pki_validator.addCertificates(mCerts);
|
||||||
|
pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash);
|
||||||
|
}
|
||||||
|
catch (const fnd::Exception& e)
|
||||||
|
{
|
||||||
|
std::cout << "[WARNING] Ticket signature could not be validated (" << e.error() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EsTikProcess::displayTicket()
|
||||||
|
{
|
||||||
|
#define _SPLIT_VER(ver) ( (ver>>10) & 0x3f), ( (ver>>4) & 0x3f), ( (ver>>0) & 0xf)
|
||||||
|
#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0)
|
||||||
|
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
|
||||||
|
|
||||||
|
const es::TicketBody_V2& body = mTik.getBody();
|
||||||
|
|
||||||
|
std::cout << "[ES Ticket]" << std::endl;
|
||||||
|
|
||||||
|
std::cout << " SignType: " << getSignTypeStr(mTik.getSignature().getSignType());
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
std::cout << " (0x" << std::hex << mTik.getSignature().getSignType() << ")";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << " Issuer: " << body.getIssuer() << std::endl;
|
||||||
|
std::cout << " Title Key:" << std::endl;
|
||||||
|
std::cout << " EncMode: " << getTitleKeyPersonalisationStr(body.getTitleKeyEncType()) << std::endl;
|
||||||
|
std::cout << " KeyGeneration: " << std::dec << (uint32_t)body.getCommonKeyId() << std::endl;
|
||||||
|
std::cout << " Data:" << std::endl;
|
||||||
|
size_t size = body.getTitleKeyEncType() == es::ticket::RSA2048 ? crypto::rsa::kRsa2048Size : crypto::aes::kAes128KeySize;
|
||||||
|
fnd::SimpleTextOutput::hexDump(body.getEncTitleKey(), size, 0x10, 6);
|
||||||
|
|
||||||
|
printf(" Version: v%d.%d.%d", _SPLIT_VER(body.getTicketVersion()));
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
printf(" (%d)", body.getTicketVersion());
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
std::cout << " License Type: " << getLicenseTypeStr(body.getLicenseType()) << std::endl;
|
||||||
|
|
||||||
|
if (body.getPropertyFlags().size() > 0)
|
||||||
|
{
|
||||||
|
std::cout << " Flags:" << std::endl;
|
||||||
|
for (size_t i = 0; i < body.getPropertyFlags().size(); i++)
|
||||||
|
{
|
||||||
|
std::cout << " " << getPropertyFlagStr(body.getPropertyFlags()[i]) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
{
|
||||||
|
std::cout << " Reserved Region:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(body.getReservedRegion(), 8, 0x10, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body.getTicketId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
std::cout << " TicketId: 0x" << std::hex << std::setw(16) << std::setfill('0') << body.getTicketId() << std::endl;
|
||||||
|
|
||||||
|
if (body.getDeviceId() != 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
std::cout << " DeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << body.getDeviceId() << std::endl;
|
||||||
|
|
||||||
|
std::cout << " RightsId: " << std::endl << " ";
|
||||||
|
fnd::SimpleTextOutput::hexDump(body.getRightsId(), 16);
|
||||||
|
|
||||||
|
std::cout << " SectionTotalSize: 0x" << std::hex << body.getSectionTotalSize() << std::endl;
|
||||||
|
std::cout << " SectionHeaderOffset: 0x" << std::hex << body.getSectionHeaderOffset() << std::endl;
|
||||||
|
std::cout << " SectionNum: 0x" << std::hex << body.getSectionNum() << std::endl;
|
||||||
|
std::cout << " SectionEntrySize: 0x" << std::hex << body.getSectionEntrySize() << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
#undef _HEXDUMP_L
|
||||||
|
#undef _HEXDUMP_U
|
||||||
|
#undef _SPLIT_VER
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* EsTikProcess::getSignTypeStr(uint32_t type) const
|
||||||
|
{
|
||||||
|
const char* str = nullptr;
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA1):
|
||||||
|
str = "RSA4096-SHA1";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA1):
|
||||||
|
str = "RSA2048-SHA1";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
|
str = "ECDSA240-SHA1";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA256):
|
||||||
|
str = "RSA4096-SHA256";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA256):
|
||||||
|
str = "RSA2048-SHA256";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
|
str = "ECDSA240-SHA256";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* EsTikProcess::getTitleKeyPersonalisationStr(byte_t flag) const
|
||||||
|
{
|
||||||
|
const char* str = nullptr;
|
||||||
|
switch(flag)
|
||||||
|
{
|
||||||
|
case (es::ticket::AES128_CBC):
|
||||||
|
str = "Generic (AESCBC)";
|
||||||
|
break;
|
||||||
|
case (es::ticket::RSA2048):
|
||||||
|
str = "Personalised (RSA2048)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* EsTikProcess::getLicenseTypeStr(byte_t flag) const
|
||||||
|
{
|
||||||
|
const char* str = nullptr;
|
||||||
|
switch(flag)
|
||||||
|
{
|
||||||
|
case (es::ticket::LICENSE_PERMANENT):
|
||||||
|
str = "Permanent";
|
||||||
|
break;
|
||||||
|
case (es::ticket::LICENSE_DEMO):
|
||||||
|
str = "Demo";
|
||||||
|
break;
|
||||||
|
case (es::ticket::LICENSE_TRIAL):
|
||||||
|
str = "Trial";
|
||||||
|
break;
|
||||||
|
case (es::ticket::LICENSE_RENTAL):
|
||||||
|
str = "Rental";
|
||||||
|
break;
|
||||||
|
case (es::ticket::LICENSE_SUBSCRIPTION):
|
||||||
|
str = "Subscription";
|
||||||
|
break;
|
||||||
|
case (es::ticket::LICENSE_SERVICE):
|
||||||
|
str = "Service";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* EsTikProcess::getPropertyFlagStr(byte_t flag) const
|
||||||
|
{
|
||||||
|
const char* str = nullptr;
|
||||||
|
switch(flag)
|
||||||
|
{
|
||||||
|
case (es::ticket::FLAG_PRE_INSTALL):
|
||||||
|
str = "PreInstall";
|
||||||
|
break;
|
||||||
|
case (es::ticket::FLAG_SHARED_TITLE):
|
||||||
|
str = "SharedTitle";
|
||||||
|
break;
|
||||||
|
case (es::ticket::FLAG_ALLOW_ALL_CONTENT):
|
||||||
|
str = "AllContent";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
45
programs/nstool/source/EsTikProcess.h
Normal file
45
programs/nstool/source/EsTikProcess.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <fnd/types.h>
|
||||||
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/Vec.h>
|
||||||
|
#include <pki/SignedData.h>
|
||||||
|
#include <pki/CertificateBody.h>
|
||||||
|
#include <es/TicketBody_V2.h>
|
||||||
|
#include "nstool.h"
|
||||||
|
|
||||||
|
class EsTikProcess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EsTikProcess();
|
||||||
|
~EsTikProcess();
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||||
|
void setKeyset(const sKeyset* keyset);
|
||||||
|
void setCertificateChain(const fnd::List<pki::SignedData<pki::CertificateBody>>& certs);
|
||||||
|
void setCliOutputMode(CliOutputMode mode);
|
||||||
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string kModuleName = "EsTikProcess";
|
||||||
|
|
||||||
|
fnd::IFile* mFile;
|
||||||
|
bool mOwnIFile;
|
||||||
|
const sKeyset* mKeyset;
|
||||||
|
CliOutputMode mCliOutputMode;
|
||||||
|
bool mVerify;
|
||||||
|
|
||||||
|
fnd::List<pki::SignedData<pki::CertificateBody>> mCerts;
|
||||||
|
|
||||||
|
pki::SignedData<es::TicketBody_V2> mTik;
|
||||||
|
|
||||||
|
void importTicket();
|
||||||
|
void verifyTicket();
|
||||||
|
void displayTicket();
|
||||||
|
const char* getSignTypeStr(uint32_t type) const;
|
||||||
|
const char* getTitleKeyPersonalisationStr(byte_t flag) const;
|
||||||
|
const char* getLicenseTypeStr(byte_t flag) const;
|
||||||
|
const char* getPropertyFlagStr(byte_t flag) const;
|
||||||
|
};
|
|
@ -286,27 +286,6 @@ void NcaProcess::process()
|
||||||
|
|
||||||
// process partition
|
// process partition
|
||||||
processPartitions();
|
processPartitions();
|
||||||
|
|
||||||
/*
|
|
||||||
NCA is a file container
|
|
||||||
A hashed and signed file container
|
|
||||||
|
|
||||||
To verify a NCA: (R=regular step)
|
|
||||||
1 - decrypt header (R)
|
|
||||||
2 - verify signature[0]
|
|
||||||
3 - validate hashes of fs_headers
|
|
||||||
4 - determine how to read/decrypt the partitions (R)
|
|
||||||
5 - validate the partitions depending on their hash method
|
|
||||||
6 - if this NCA is a Program or Patch, open main.npdm from partition0
|
|
||||||
7 - validate ACID
|
|
||||||
8 - use public key in ACID to verify NCA signature[1]
|
|
||||||
|
|
||||||
Things to consider
|
|
||||||
* because of the manditory steps between verifcation steps
|
|
||||||
the NCA should be ready to be pulled to pieces before any printing is done
|
|
||||||
so the verification text can be presented without interuption
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||||
|
@ -695,9 +674,10 @@ void NcaProcess::displayHeader()
|
||||||
printf(" Partitions:\n");
|
printf(" Partitions:\n");
|
||||||
for (size_t i = 0; i < mHdr.getPartitions().size(); i++)
|
for (size_t i = 0; i < mHdr.getPartitions().size(); i++)
|
||||||
{
|
{
|
||||||
sPartitionInfo& info = mPartitions[i];
|
size_t index = mHdr.getPartitions()[i].index;
|
||||||
|
sPartitionInfo& info = mPartitions[index];
|
||||||
|
|
||||||
printf(" %d:\n", (int)i);
|
printf(" %d:\n", (int)index);
|
||||||
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
|
printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
|
||||||
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
|
printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
|
||||||
printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
|
printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
|
||||||
|
@ -790,7 +770,7 @@ void NcaProcess::processPartitions()
|
||||||
pfs.setListFs(mListFs);
|
pfs.setListFs(mListFs);
|
||||||
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
|
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
|
||||||
{
|
{
|
||||||
pfs.setMountPointName(std::string(getContentTypeForMountStr(mHdr.getContentType())) + ":/" + std::string(getProgramPartitionNameStr(i)));
|
pfs.setMountPointName(std::string(getContentTypeForMountStr(mHdr.getContentType())) + ":/" + std::string(getProgramPartitionNameStr(index)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -811,7 +791,7 @@ void NcaProcess::processPartitions()
|
||||||
romfs.setListFs(mListFs);
|
romfs.setListFs(mListFs);
|
||||||
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
|
if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM)
|
||||||
{
|
{
|
||||||
romfs.setMountPointName(std::string(getContentTypeForMountStr(mHdr.getContentType())) + ":/" + std::string(getProgramPartitionNameStr(i)));
|
romfs.setMountPointName(std::string(getContentTypeForMountStr(mHdr.getContentType())) + ":/" + std::string(getProgramPartitionNameStr(index)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
213
programs/nstool/source/PkiCertProcess.cpp
Normal file
213
programs/nstool/source/PkiCertProcess.cpp
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <pki/SignUtils.h>
|
||||||
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
#include "PkiCertProcess.h"
|
||||||
|
#include "PkiValidator.h"
|
||||||
|
|
||||||
|
PkiCertProcess::PkiCertProcess() :
|
||||||
|
mFile(nullptr),
|
||||||
|
mOwnIFile(false),
|
||||||
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
|
mVerify(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PkiCertProcess::~PkiCertProcess()
|
||||||
|
{
|
||||||
|
if (mOwnIFile)
|
||||||
|
{
|
||||||
|
delete mFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::process()
|
||||||
|
{
|
||||||
|
if (mFile == nullptr)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
importCerts();
|
||||||
|
if (mVerify)
|
||||||
|
validateCerts();
|
||||||
|
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||||
|
displayCerts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||||
|
{
|
||||||
|
mFile = file;
|
||||||
|
mOwnIFile = ownIFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::setKeyset(const sKeyset* keyset)
|
||||||
|
{
|
||||||
|
mKeyset = keyset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::setCliOutputMode(CliOutputMode mode)
|
||||||
|
{
|
||||||
|
mCliOutputMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::setVerifyMode(bool verify)
|
||||||
|
{
|
||||||
|
mVerify = verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::importCerts()
|
||||||
|
{
|
||||||
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
scratch.alloc(mFile->size());
|
||||||
|
mFile->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
|
pki::SignedData<pki::CertificateBody> cert;
|
||||||
|
for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size())
|
||||||
|
{
|
||||||
|
cert.fromBytes(scratch.data() + f_pos, scratch.size() - f_pos);
|
||||||
|
mCert.addElement(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::validateCerts()
|
||||||
|
{
|
||||||
|
PkiValidator pki;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pki.setRootKey(mKeyset->pki.root_sign_key);
|
||||||
|
pki.addCertificates(mCert);
|
||||||
|
}
|
||||||
|
catch (const fnd::Exception& e)
|
||||||
|
{
|
||||||
|
std::cout << "[WARNING] " << e.error() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::displayCerts()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < mCert.size(); i++)
|
||||||
|
{
|
||||||
|
displayCert(mCert[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiCertProcess::displayCert(const pki::SignedData<pki::CertificateBody>& cert)
|
||||||
|
{
|
||||||
|
#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff)
|
||||||
|
#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0)
|
||||||
|
#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
|
||||||
|
|
||||||
|
std::cout << "[NNPKI Certificate]" << std::endl;
|
||||||
|
|
||||||
|
std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType());
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
std::cout << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian());
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl;
|
||||||
|
std::cout << " Subject: " << cert.getBody().getSubject() << std::endl;
|
||||||
|
std::cout << " PublicKeyType: " << getPublicKeyTypeStr(cert.getBody().getPublicKeyType());
|
||||||
|
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||||
|
std::cout << " (" << std::dec << cert.getBody().getPublicKeyType() << ")";
|
||||||
|
std::cout << std::endl;
|
||||||
|
std::cout << " CertID: 0x" << std::hex << cert.getBody().getCertId() << std::endl;
|
||||||
|
|
||||||
|
if (cert.getBody().getPublicKeyType() == pki::cert::RSA4096)
|
||||||
|
{
|
||||||
|
std::cout << " PublicKey:" << std::endl;
|
||||||
|
std::cout << " Modulus:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa4098PublicKey().modulus, getHexDumpLen(crypto::rsa::kRsa4096Size), 0x10, 6);
|
||||||
|
std::cout << " Public Exponent:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa4098PublicKey().public_exponent, crypto::rsa::kRsaPublicExponentSize, 0x10, 6);
|
||||||
|
}
|
||||||
|
else if (cert.getBody().getPublicKeyType() == pki::cert::RSA2048)
|
||||||
|
{
|
||||||
|
std::cout << " PublicKey:" << std::endl;
|
||||||
|
std::cout << " Public Exponent:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().modulus, getHexDumpLen(crypto::rsa::kRsa2048Size), 0x10, 6);
|
||||||
|
std::cout << " Modulus:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().public_exponent, crypto::rsa::kRsaPublicExponentSize, 0x10, 6);
|
||||||
|
}
|
||||||
|
else if (cert.getBody().getPublicKeyType() == pki::cert::ECDSA240)
|
||||||
|
{
|
||||||
|
std::cout << " PublicKey:" << std::endl;
|
||||||
|
std::cout << " R:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getEcdsa240PublicKey().r, getHexDumpLen(crypto::ecdsa::kEcdsa240Size), 0x10, 6);
|
||||||
|
std::cout << " S:" << std::endl;
|
||||||
|
fnd::SimpleTextOutput::hexDump(cert.getBody().getEcdsa240PublicKey().s, getHexDumpLen(crypto::ecdsa::kEcdsa240Size), 0x10, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#undef _HEXDUMP_L
|
||||||
|
#undef _HEXDUMP_U
|
||||||
|
#undef _SPLIT_VER
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t PkiCertProcess::getHexDumpLen(size_t max_size) const
|
||||||
|
{
|
||||||
|
return _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED) ? max_size : kSmallHexDumpLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* PkiCertProcess::getSignTypeStr(pki::sign::SignatureId type) const
|
||||||
|
{
|
||||||
|
const char* str;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA1):
|
||||||
|
str = "RSA4096-SHA1";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA1):
|
||||||
|
str = "RSA2048-SHA1";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA1):
|
||||||
|
str = "ECDSA240-SHA1";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA4096_SHA256):
|
||||||
|
str = "RSA4096-SHA256";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_RSA2048_SHA256):
|
||||||
|
str = "RSA2048-SHA256";
|
||||||
|
break;
|
||||||
|
case (pki::sign::SIGN_ID_ECDSA240_SHA256):
|
||||||
|
str = "ECDSA240-SHA256";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* PkiCertProcess::getEndiannessStr(bool isLittleEndian) const
|
||||||
|
{
|
||||||
|
return isLittleEndian ? "LittleEndian" : "BigEndian";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* PkiCertProcess::getPublicKeyTypeStr(pki::cert::PublicKeyType type) const
|
||||||
|
{
|
||||||
|
const char* str;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case (pki::cert::RSA4096):
|
||||||
|
str = "RSA4096";
|
||||||
|
break;
|
||||||
|
case (pki::cert::RSA2048):
|
||||||
|
str = "RSA2048";
|
||||||
|
break;
|
||||||
|
case (pki::cert::ECDSA240):
|
||||||
|
str = "ECDSA240";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
45
programs/nstool/source/PkiCertProcess.h
Normal file
45
programs/nstool/source/PkiCertProcess.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <fnd/types.h>
|
||||||
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
|
#include <fnd/Vec.h>
|
||||||
|
#include <pki/SignedData.h>
|
||||||
|
#include <pki/CertificateBody.h>
|
||||||
|
#include "nstool.h"
|
||||||
|
|
||||||
|
class PkiCertProcess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PkiCertProcess();
|
||||||
|
~PkiCertProcess();
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||||
|
void setKeyset(const sKeyset* keyset);
|
||||||
|
void setCliOutputMode(CliOutputMode type);
|
||||||
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string kModuleName = "PkiCertProcess";
|
||||||
|
static const size_t kSmallHexDumpLen = 0x10;
|
||||||
|
|
||||||
|
fnd::IFile* mFile;
|
||||||
|
bool mOwnIFile;
|
||||||
|
const sKeyset* mKeyset;
|
||||||
|
CliOutputMode mCliOutputMode;
|
||||||
|
bool mVerify;
|
||||||
|
|
||||||
|
fnd::List<pki::SignedData<pki::CertificateBody>> mCert;
|
||||||
|
|
||||||
|
void importCerts();
|
||||||
|
void validateCerts();
|
||||||
|
void displayCerts();
|
||||||
|
void displayCert(const pki::SignedData<pki::CertificateBody>& cert);
|
||||||
|
|
||||||
|
size_t getHexDumpLen(size_t max_size) const;
|
||||||
|
const char* getSignTypeStr(pki::sign::SignatureId type) const;
|
||||||
|
const char* getEndiannessStr(bool isLittleEndian) const;
|
||||||
|
const char* getPublicKeyTypeStr(pki::cert::PublicKeyType type) const;
|
||||||
|
};
|
197
programs/nstool/source/PkiValidator.cpp
Normal file
197
programs/nstool/source/PkiValidator.cpp
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
#include "PkiValidator.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <pki/SignUtils.h>
|
||||||
|
|
||||||
|
PkiValidator::PkiValidator()
|
||||||
|
{
|
||||||
|
clearCertificates();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::setRootKey(const crypto::rsa::sRsa4096Key& root_key)
|
||||||
|
{
|
||||||
|
// save a copy of the certificate bank
|
||||||
|
fnd::List<pki::SignedData<pki::CertificateBody>> old_certs = mCertificateBank;
|
||||||
|
|
||||||
|
// clear the certificate bank
|
||||||
|
mCertificateBank.clear();
|
||||||
|
|
||||||
|
// overwrite the root key
|
||||||
|
mRootKey = root_key;
|
||||||
|
|
||||||
|
// if there were certificates before, reimport them (so they are checked against the new root key)
|
||||||
|
if (old_certs.size() > 0)
|
||||||
|
{
|
||||||
|
addCertificates(old_certs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::addCertificates(const fnd::List<pki::SignedData<pki::CertificateBody>>& certs)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < certs.size(); i++)
|
||||||
|
{
|
||||||
|
addCertificate(certs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::addCertificate(const pki::SignedData<pki::CertificateBody>& cert)
|
||||||
|
{
|
||||||
|
std::string cert_ident;
|
||||||
|
pki::sign::SignatureAlgo cert_sign_algo;
|
||||||
|
pki::sign::HashAlgo cert_hash_algo;
|
||||||
|
fnd::Vec<byte_t> cert_hash;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
makeCertIdent(cert, cert_ident);
|
||||||
|
|
||||||
|
if (doesCertExist(cert_ident) == true)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "Certificate already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_sign_algo = pki::sign::getSignatureAlgo(cert.getSignature().getSignType());
|
||||||
|
cert_hash_algo = pki::sign::getHashAlgo(cert.getSignature().getSignType());
|
||||||
|
|
||||||
|
// get cert hash
|
||||||
|
switch (cert_hash_algo)
|
||||||
|
{
|
||||||
|
case (pki::sign::HASH_ALGO_SHA1):
|
||||||
|
cert_hash.alloc(crypto::sha::kSha1HashLen);
|
||||||
|
crypto::sha::Sha1(cert.getBody().getBytes().data(), cert.getBody().getBytes().size(), cert_hash.data());
|
||||||
|
break;
|
||||||
|
case (pki::sign::HASH_ALGO_SHA256):
|
||||||
|
cert_hash.alloc(crypto::sha::kSha256HashLen);
|
||||||
|
crypto::sha::Sha256(cert.getBody().getBytes().data(), cert.getBody().getBytes().size(), cert_hash.data());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw fnd::Exception(kModuleName, "Unrecognised hash type");
|
||||||
|
}
|
||||||
|
|
||||||
|
validateSignature(cert.getBody().getIssuer(), cert.getSignature().getSignType(), cert.getSignature().getSignature(), cert_hash);
|
||||||
|
|
||||||
|
mCertificateBank.addElement(cert);
|
||||||
|
}
|
||||||
|
catch (const fnd::Exception& e)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Failed to add certificate " << cert_ident << " (" << e.error() << ")";
|
||||||
|
throw fnd::Exception(kModuleName, ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::clearCertificates()
|
||||||
|
{
|
||||||
|
mCertificateBank.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::validateSignature(const std::string& issuer, pki::sign::SignatureId signature_id, const fnd::Vec<byte_t>& signature, const fnd::Vec<byte_t>& hash) const
|
||||||
|
{
|
||||||
|
pki::sign::SignatureAlgo sign_algo = pki::sign::getSignatureAlgo(signature_id);
|
||||||
|
pki::sign::HashAlgo hash_algo = pki::sign::getHashAlgo(signature_id);
|
||||||
|
|
||||||
|
|
||||||
|
// validate signature
|
||||||
|
int sig_validate_res = -1;
|
||||||
|
|
||||||
|
// special case if signed by Root
|
||||||
|
if (issuer == pki::sign::kRootIssuerStr)
|
||||||
|
{
|
||||||
|
if (sign_algo != pki::sign::SIGN_ALGO_RSA4096)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "Issued by Root, but does not have a RSA4096 signature");
|
||||||
|
}
|
||||||
|
sig_validate_res = crypto::rsa::pkcs::rsaVerify(mRootKey, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// try to find issuer cert
|
||||||
|
const pki::CertificateBody& issuer_cert = getCert(issuer).getBody();
|
||||||
|
pki::cert::PublicKeyType issuer_pubk_type = issuer_cert.getPublicKeyType();
|
||||||
|
|
||||||
|
if (issuer_pubk_type == pki::cert::RSA4096 && sign_algo == pki::sign::SIGN_ALGO_RSA4096)
|
||||||
|
{
|
||||||
|
sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer_cert.getRsa4098PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||||
|
}
|
||||||
|
else if (issuer_pubk_type == pki::cert::RSA2048 && sign_algo == pki::sign::SIGN_ALGO_RSA2048)
|
||||||
|
{
|
||||||
|
sig_validate_res = crypto::rsa::pkcs::rsaVerify(issuer_cert.getRsa2048PublicKey(), getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||||
|
}
|
||||||
|
else if (issuer_pubk_type == pki::cert::ECDSA240 && sign_algo == pki::sign::SIGN_ALGO_ECDSA240)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "ECDSA signatures are not supported");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "Mismatch between issuer public key and signature type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sig_validate_res != 0)
|
||||||
|
{
|
||||||
|
throw fnd::Exception(kModuleName, "Incorrect signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::makeCertIdent(const pki::SignedData<pki::CertificateBody>& cert, std::string& ident) const
|
||||||
|
{
|
||||||
|
makeCertIdent(cert.getBody().getIssuer(), cert.getBody().getSubject(), ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PkiValidator::makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const
|
||||||
|
{
|
||||||
|
ident = issuer + pki::sign::kIdentDelimiter + subject;
|
||||||
|
ident = ident.substr(0, _MIN(ident.length(),64));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PkiValidator::doesCertExist(const std::string& ident) const
|
||||||
|
{
|
||||||
|
bool exists = false;
|
||||||
|
std::string full_cert_name;
|
||||||
|
for (size_t i = 0; i < mCertificateBank.size(); i++)
|
||||||
|
{
|
||||||
|
makeCertIdent(mCertificateBank[i], full_cert_name);
|
||||||
|
if (full_cert_name == ident)
|
||||||
|
{
|
||||||
|
exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pki::SignedData<pki::CertificateBody>& PkiValidator::getCert(const std::string& ident) const
|
||||||
|
{
|
||||||
|
std::string full_cert_name;
|
||||||
|
for (size_t i = 0; i < mCertificateBank.size(); i++)
|
||||||
|
{
|
||||||
|
makeCertIdent(mCertificateBank[i], full_cert_name);
|
||||||
|
if (full_cert_name == ident)
|
||||||
|
{
|
||||||
|
return mCertificateBank[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw fnd::Exception(kModuleName, "Issuer certificate does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto::sha::HashType PkiValidator::getCryptoHashAlgoFromEsSignHashAlgo(pki::sign::HashAlgo hash_algo) const
|
||||||
|
{
|
||||||
|
crypto::sha::HashType hash_type = crypto::sha::HASH_SHA1;
|
||||||
|
|
||||||
|
switch (hash_algo)
|
||||||
|
{
|
||||||
|
case (pki::sign::HASH_ALGO_SHA1):
|
||||||
|
hash_type = crypto::sha::HASH_SHA1;
|
||||||
|
break;
|
||||||
|
case (pki::sign::HASH_ALGO_SHA256):
|
||||||
|
hash_type = crypto::sha::HASH_SHA256;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
return hash_type;
|
||||||
|
}
|
34
programs/nstool/source/PkiValidator.h
Normal file
34
programs/nstool/source/PkiValidator.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fnd/types.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
|
#include <fnd/Vec.h>
|
||||||
|
#include <crypto/rsa.h>
|
||||||
|
#include <pki/SignedData.h>
|
||||||
|
#include <pki/CertificateBody.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class PkiValidator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PkiValidator();
|
||||||
|
|
||||||
|
void setRootKey(const crypto::rsa::sRsa4096Key& root_key);
|
||||||
|
void addCertificates(const fnd::List<pki::SignedData<pki::CertificateBody>>& certs);
|
||||||
|
void addCertificate(const pki::SignedData<pki::CertificateBody>& cert);
|
||||||
|
void clearCertificates();
|
||||||
|
|
||||||
|
void validateSignature(const std::string& issuer, pki::sign::SignatureId signature_id, const fnd::Vec<byte_t>& signature, const fnd::Vec<byte_t>& hash) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string kModuleName = "NNPkiValidator";
|
||||||
|
|
||||||
|
|
||||||
|
crypto::rsa::sRsa4096Key mRootKey;
|
||||||
|
fnd::List<pki::SignedData<pki::CertificateBody>> mCertificateBank;
|
||||||
|
|
||||||
|
void makeCertIdent(const pki::SignedData<pki::CertificateBody>& cert, std::string& ident) const;
|
||||||
|
void makeCertIdent(const std::string& issuer, const std::string& subject, std::string& ident) const;
|
||||||
|
bool doesCertExist(const std::string& ident) const;
|
||||||
|
const pki::SignedData<pki::CertificateBody>& getCert(const std::string& ident) const;
|
||||||
|
crypto::sha::HashType getCryptoHashAlgoFromEsSignHashAlgo(pki::sign::HashAlgo hash_algo) const;
|
||||||
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
#include "UserSettings.h"
|
#include "UserSettings.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "PkiValidator.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -22,6 +23,10 @@
|
||||||
#include <nx/nso.h>
|
#include <nx/nso.h>
|
||||||
#include <nx/nro.h>
|
#include <nx/nro.h>
|
||||||
#include <nx/aset.h>
|
#include <nx/aset.h>
|
||||||
|
#include <pki/SignedData.h>
|
||||||
|
#include <pki/CertificateBody.h>
|
||||||
|
#include <pki/SignUtils.h>
|
||||||
|
#include <es/TicketBody_V2.h>
|
||||||
|
|
||||||
UserSettings::UserSettings()
|
UserSettings::UserSettings()
|
||||||
{}
|
{}
|
||||||
|
@ -41,34 +46,36 @@ void UserSettings::showHelp()
|
||||||
|
|
||||||
printf("Usage: nstool [options... ] <file>\n");
|
printf("Usage: nstool [options... ] <file>\n");
|
||||||
printf("\n General Options:\n");
|
printf("\n General Options:\n");
|
||||||
printf(" -d, --dev Use devkit keyset\n");
|
printf(" -d, --dev Use devkit keyset.\n");
|
||||||
printf(" -k, --keyset Specify keyset file\n");
|
printf(" -k, --keyset Specify keyset file.\n");
|
||||||
printf(" -t, --type Specify input file type [xci, pfs, romfs, nca, npdm, cnmt, nso, nro, nacp, aset]\n");
|
printf(" -t, --type Specify input file type. [xci, pfs, romfs, nca, npdm, cnmt, nso, nro, nacp, aset, cert, tik]\n");
|
||||||
printf(" -y, --verify Verify file\n");
|
printf(" -y, --verify Verify file.\n");
|
||||||
printf("\n Output Options:\n");
|
printf("\n Output Options:\n");
|
||||||
printf(" --showkeys Show keys generated\n");
|
printf(" --showkeys Show keys generated.\n");
|
||||||
printf(" --showlayout Show layout metadata\n");
|
printf(" --showlayout Show layout metadata.\n");
|
||||||
printf(" -v, --verbose Verbose output\n");
|
printf(" -v, --verbose Verbose output.\n");
|
||||||
printf("\n XCI (GameCard Image)\n");
|
printf("\n XCI (GameCard Image)\n");
|
||||||
printf(" nstool [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n");
|
printf(" nstool [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n");
|
||||||
printf(" --listfs Print file system in embedded partitions\n");
|
printf(" --listfs Print file system in embedded partitions.\n");
|
||||||
printf(" --update Extract \"update\" partition to directory\n");
|
printf(" --update Extract \"update\" partition to directory.\n");
|
||||||
printf(" --logo Extract \"logo\" partition to directory\n");
|
printf(" --logo Extract \"logo\" partition to directory.\n");
|
||||||
printf(" --normal Extract \"normal\" partition to directory\n");
|
printf(" --normal Extract \"normal\" partition to directory.\n");
|
||||||
printf(" --secure Extract \"secure\" partition to directory\n");
|
printf(" --secure Extract \"secure\" partition to directory.\n");
|
||||||
printf("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n");
|
printf("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n");
|
||||||
printf(" nstool [--listfs] [--fsdir <dir>] <file>\n");
|
printf(" nstool [--listfs] [--fsdir <dir>] <file>\n");
|
||||||
printf(" --listfs Print file system\n");
|
printf(" --listfs Print file system.\n");
|
||||||
printf(" --fsdir Extract file system to directory\n");
|
printf(" --fsdir Extract file system to directory.\n");
|
||||||
printf("\n NCA (Nintendo Content Archive)\n");
|
printf("\n NCA (Nintendo Content Archive)\n");
|
||||||
printf(" nstool [--listfs] [--bodykey <key> --titlekey <key>] [--part0 <dir> ...] <.nca file>\n");
|
printf(" nstool [--listfs] [--bodykey <key> --titlekey <key>] [--part0 <dir> ...] <.nca file>\n");
|
||||||
printf(" --listfs Print file system in embedded partitions\n");
|
printf(" --listfs Print file system in embedded partitions.\n");
|
||||||
printf(" --titlekey Specify title key extracted from ticket\n");
|
printf(" --titlekey Specify title key extracted from ticket.\n");
|
||||||
printf(" --bodykey Specify body encryption key\n");
|
printf(" --bodykey Specify body encryption key.\n");
|
||||||
printf(" --part0 Extract \"partition 0\" to directory \n");
|
printf(" --tik Specify ticket to source title key.\n");
|
||||||
printf(" --part1 Extract \"partition 1\" to directory \n");
|
printf(" --cert Specify certificate chain to verify ticket.\n");
|
||||||
printf(" --part2 Extract \"partition 2\" to directory \n");
|
printf(" --part0 Extract \"partition 0\" to directory.\n");
|
||||||
printf(" --part3 Extract \"partition 3\" to directory \n");
|
printf(" --part1 Extract \"partition 1\" to directory.\n");
|
||||||
|
printf(" --part2 Extract \"partition 2\" to directory.\n");
|
||||||
|
printf(" --part3 Extract \"partition 3\" to directory.\n");
|
||||||
printf("\n NSO (Nintendo Software Object), NRO (Nintendo Relocatable Object)\n");
|
printf("\n NSO (Nintendo Software Object), NRO (Nintendo Relocatable Object)\n");
|
||||||
printf(" nstool [--listapi --listsym] [--insttype <inst. type>] <file>\n");
|
printf(" nstool [--listapi --listsym] [--insttype <inst. type>] <file>\n");
|
||||||
printf(" --listapi Print SDK API List.\n");
|
printf(" --listapi Print SDK API List.\n");
|
||||||
|
@ -182,6 +189,11 @@ const sOptional<std::string>& UserSettings::getAssetNacpPath() const
|
||||||
return mAssetNacpPath;
|
return mAssetNacpPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fnd::List<pki::SignedData<pki::CertificateBody>>& UserSettings::getCertificateChain() const
|
||||||
|
{
|
||||||
|
return mCertChain;
|
||||||
|
}
|
||||||
|
|
||||||
void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCmdArgs& cmd_args)
|
void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCmdArgs& cmd_args)
|
||||||
{
|
{
|
||||||
// show help text
|
// show help text
|
||||||
|
@ -296,6 +308,18 @@ void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCm
|
||||||
cmd_args.nca_bodykey = arg_list[i+1];
|
cmd_args.nca_bodykey = arg_list[i+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (arg_list[i] == "--tik")
|
||||||
|
{
|
||||||
|
if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter.");
|
||||||
|
cmd_args.ticket_path = arg_list[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (arg_list[i] == "--cert")
|
||||||
|
{
|
||||||
|
if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter.");
|
||||||
|
cmd_args.cert_path = arg_list[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
else if (arg_list[i] == "--part0")
|
else if (arg_list[i] == "--part0")
|
||||||
{
|
{
|
||||||
if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter.");
|
if (!hasParamter) throw fnd::Exception(kModuleName, arg_list[i] + " requries a parameter.");
|
||||||
|
@ -415,6 +439,7 @@ void UserSettings::populateKeyset(sCmdArgs& args)
|
||||||
const std::string kKekGenSource = "aes_kek_generation";
|
const std::string kKekGenSource = "aes_kek_generation";
|
||||||
const std::string kKeyGenSource = "aes_key_generation";
|
const std::string kKeyGenSource = "aes_key_generation";
|
||||||
const std::string kAcidBase = "acid";
|
const std::string kAcidBase = "acid";
|
||||||
|
const std::string kPkiRootBase = "pki_root";
|
||||||
const std::string kTicketCommonKeyBase[2] = { "titlekek", "ticket_commonkey" };
|
const std::string kTicketCommonKeyBase[2] = { "titlekek", "ticket_commonkey" };
|
||||||
const std::string kNcaBodyBase[2] = {"key_area_key", "nca_body_keak"};
|
const std::string kNcaBodyBase[2] = {"key_area_key", "nca_body_keak"};
|
||||||
const std::string kNcaBodyKeakIndexName[3] = {"application", "ocean", "system"};
|
const std::string kNcaBodyKeakIndexName[3] = {"application", "ocean", "system"};
|
||||||
|
@ -484,17 +509,21 @@ void UserSettings::populateKeyset(sCmdArgs& args)
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kKeyStr), mKeyset.xci.header_key.key, 0x10);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kKeyStr), mKeyset.xci.header_key.key, 0x10);
|
||||||
|
|
||||||
// store rsa keys
|
// store rsa keys
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[0]), mKeyset.nca.header_sign_key.priv_exponent, 0x100);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[0]), mKeyset.nca.header_sign_key.priv_exponent, crypto::rsa::kRsa2048Size);
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[1]), mKeyset.nca.header_sign_key.modulus, 0x100);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[1]), mKeyset.nca.header_sign_key.modulus, crypto::rsa::kRsa2048Size);
|
||||||
|
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[0]), mKeyset.xci.header_sign_key.priv_exponent, 0x100);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[0]), mKeyset.xci.header_sign_key.priv_exponent, crypto::rsa::kRsa2048Size);
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[1]), mKeyset.xci.header_sign_key.modulus, 0x100);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[1]), mKeyset.xci.header_sign_key.modulus, crypto::rsa::kRsa2048Size);
|
||||||
|
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[0]), mKeyset.acid_sign_key.priv_exponent, 0x100);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[0]), mKeyset.acid_sign_key.priv_exponent, crypto::rsa::kRsa2048Size);
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[1]), mKeyset.acid_sign_key.modulus, 0x100);
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[1]), mKeyset.acid_sign_key.modulus, crypto::rsa::kRsa2048Size);
|
||||||
|
|
||||||
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[0]), mKeyset.package2_sign_key.priv_exponent, crypto::rsa::kRsa2048Size);
|
||||||
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[1]), mKeyset.package2_sign_key.modulus, crypto::rsa::kRsa2048Size);
|
||||||
|
|
||||||
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase, kRsaKeySuffix[0]), mKeyset.pki.root_sign_key.priv_exponent, crypto::rsa::kRsa4096Size);
|
||||||
|
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase, kRsaKeySuffix[1]), mKeyset.pki.root_sign_key.modulus, crypto::rsa::kRsa4096Size);
|
||||||
|
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[0]), mKeyset.package2_sign_key.priv_exponent, 0x100);
|
|
||||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[1]), mKeyset.package2_sign_key.modulus, 0x100);
|
|
||||||
|
|
||||||
// save keydata from input args
|
// save keydata from input args
|
||||||
if (args.nca_bodykey.isSet)
|
if (args.nca_bodykey.isSet)
|
||||||
|
@ -521,6 +550,79 @@ void UserSettings::populateKeyset(sCmdArgs& args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// import certificate chain
|
||||||
|
if (args.cert_path.isSet)
|
||||||
|
{
|
||||||
|
fnd::SimpleFile cert_file;
|
||||||
|
fnd::Vec<byte_t> cert_raw;
|
||||||
|
pki::SignedData<pki::CertificateBody> cert;
|
||||||
|
|
||||||
|
cert_file.open(args.cert_path.var, fnd::SimpleFile::Read);
|
||||||
|
cert_raw.alloc(cert_file.size());
|
||||||
|
cert_file.read(cert_raw.data(), cert_raw.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cert_raw.size(); i+= cert.getBytes().size())
|
||||||
|
{
|
||||||
|
cert.fromBytes(cert_raw.data() + i, cert_raw.size() - i);
|
||||||
|
mCertChain.addElement(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get titlekey from ticket
|
||||||
|
if (args.ticket_path.isSet)
|
||||||
|
{
|
||||||
|
fnd::SimpleFile tik_file;
|
||||||
|
fnd::Vec<byte_t> tik_raw;
|
||||||
|
pki::SignedData<es::TicketBody_V2> tik;
|
||||||
|
|
||||||
|
// open and import ticket
|
||||||
|
tik_file.open(args.ticket_path.var, fnd::SimpleFile::Read);
|
||||||
|
tik_raw.alloc(tik_file.size());
|
||||||
|
tik_file.read(tik_raw.data(), tik_raw.size());
|
||||||
|
tik.fromBytes(tik_raw.data(), tik_raw.size());
|
||||||
|
|
||||||
|
// validate ticket signature
|
||||||
|
if (mCertChain.size() > 0)
|
||||||
|
{
|
||||||
|
PkiValidator pki_validator;
|
||||||
|
fnd::Vec<byte_t> tik_hash;
|
||||||
|
|
||||||
|
switch (pki::sign::getHashAlgo(tik.getSignature().getSignType()))
|
||||||
|
{
|
||||||
|
case (pki::sign::HASH_ALGO_SHA1):
|
||||||
|
tik_hash.alloc(crypto::sha::kSha1HashLen);
|
||||||
|
crypto::sha::Sha1(tik.getBody().getBytes().data(), tik.getBody().getBytes().size(), tik_hash.data());
|
||||||
|
break;
|
||||||
|
case (pki::sign::HASH_ALGO_SHA256):
|
||||||
|
tik_hash.alloc(crypto::sha::kSha256HashLen);
|
||||||
|
crypto::sha::Sha256(tik.getBody().getBytes().data(), tik.getBody().getBytes().size(), tik_hash.data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pki_validator.setRootKey(mKeyset.pki.root_sign_key);
|
||||||
|
pki_validator.addCertificates(mCertChain);
|
||||||
|
pki_validator.validateSignature(tik.getBody().getIssuer(), tik.getSignature().getSignType(), tik.getSignature().getSignature(), tik_hash);
|
||||||
|
}
|
||||||
|
catch (const fnd::Exception& e)
|
||||||
|
{
|
||||||
|
std::cout << "[WARNING] Ticket signature could not be validated (" << e.error() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract title key
|
||||||
|
if (tik.getBody().getTitleKeyEncType() == es::ticket::AES128_CBC)
|
||||||
|
{
|
||||||
|
memcpy(mKeyset.nca.manual_title_key_aesctr.key, tik.getBody().getEncTitleKey(), crypto::aes::kAes128KeySize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "[WARNING] Titlekey not imported from ticket because it is personalised" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef _SAVE_KEYDATA
|
#undef _SAVE_KEYDATA
|
||||||
#undef _CONCAT_3_STRINGS
|
#undef _CONCAT_3_STRINGS
|
||||||
#undef _CONCAT_2_STRINGS
|
#undef _CONCAT_2_STRINGS
|
||||||
|
@ -688,6 +790,10 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str)
|
||||||
type = FILE_NRO;
|
type = FILE_NRO;
|
||||||
else if (str == "nacp")
|
else if (str == "nacp")
|
||||||
type = FILE_NACP;
|
type = FILE_NACP;
|
||||||
|
else if (str == "cert")
|
||||||
|
type = FILE_PKI_CERT;
|
||||||
|
else if (str == "tik")
|
||||||
|
type = FILE_ES_TIK;
|
||||||
else if (str == "aset" || str == "asset")
|
else if (str == "aset" || str == "asset")
|
||||||
type = FILE_HB_ASSET;
|
type = FILE_HB_ASSET;
|
||||||
else
|
else
|
||||||
|
@ -746,6 +852,12 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
|
||||||
// test nso
|
// test nso
|
||||||
else if (_ASSERT_SIZE(sizeof(nx::sNroHeader)) && _TYPE_PTR(nx::sNroHeader)->st_magic.get() == nx::nro::kNroStructMagic)
|
else if (_ASSERT_SIZE(sizeof(nx::sNroHeader)) && _TYPE_PTR(nx::sNroHeader)->st_magic.get() == nx::nro::kNroStructMagic)
|
||||||
file_type = FILE_NRO;
|
file_type = FILE_NRO;
|
||||||
|
// test pki certificate
|
||||||
|
else if (determineValidEsCertFromSample(scratch))
|
||||||
|
file_type = FILE_PKI_CERT;
|
||||||
|
// test ticket
|
||||||
|
else if (determineValidEsTikFromSample(scratch))
|
||||||
|
file_type = FILE_ES_TIK;
|
||||||
// test hb asset
|
// test hb asset
|
||||||
else if (_ASSERT_SIZE(sizeof(nx::sAssetHeader)) && _TYPE_PTR(nx::sAssetHeader)->st_magic.get() == nx::aset::kAssetStructMagic)
|
else if (_ASSERT_SIZE(sizeof(nx::sAssetHeader)) && _TYPE_PTR(nx::sAssetHeader)->st_magic.get() == nx::aset::kAssetStructMagic)
|
||||||
file_type = FILE_HB_ASSET;
|
file_type = FILE_HB_ASSET;
|
||||||
|
@ -848,6 +960,50 @@ bool UserSettings::determineValidNacpFromSample(const fnd::Vec<byte_t>& sample)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UserSettings::determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const
|
||||||
|
{
|
||||||
|
pki::SignatureBlock sign;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sign.fromBytes(sample.data(), sample.size());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign.isLittleEndian() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (sign.getSignType() != pki::sign::SIGN_ID_RSA4096_SHA256 && sign.getSignType() != pki::sign::SIGN_ID_RSA2048_SHA256 && sign.getSignType() != pki::sign::SIGN_ID_ECDSA240_SHA256)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserSettings::determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample) const
|
||||||
|
{
|
||||||
|
pki::SignatureBlock sign;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sign.fromBytes(sample.data(), sample.size());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign.isLittleEndian() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (sign.getSignType() != pki::sign::SIGN_ID_RSA2048_SHA256)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
nx::npdm::InstructionType UserSettings::getInstructionTypeFromString(const std::string & type_str)
|
nx::npdm::InstructionType UserSettings::getInstructionTypeFromString(const std::string & type_str)
|
||||||
{
|
{
|
||||||
std::string str = type_str;
|
std::string str = type_str;
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
|
#include <pki/SignedData.h>
|
||||||
|
#include <pki/CertificateBody.h>
|
||||||
#include <nx/npdm.h>
|
#include <nx/npdm.h>
|
||||||
#include "nstool.h"
|
#include "nstool.h"
|
||||||
|
|
||||||
|
@ -39,6 +42,7 @@ public:
|
||||||
const sOptional<std::string>& getNcaPart3Path() const;
|
const sOptional<std::string>& getNcaPart3Path() const;
|
||||||
const sOptional<std::string>& getAssetIconPath() const;
|
const sOptional<std::string>& getAssetIconPath() const;
|
||||||
const sOptional<std::string>& getAssetNacpPath() const;
|
const sOptional<std::string>& getAssetNacpPath() const;
|
||||||
|
const fnd::List<pki::SignedData<pki::CertificateBody>>& getCertificateChain() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "UserSettings";
|
const std::string kModuleName = "UserSettings";
|
||||||
|
@ -62,6 +66,8 @@ private:
|
||||||
sOptional<std::string> fs_path;
|
sOptional<std::string> fs_path;
|
||||||
sOptional<std::string> nca_titlekey;
|
sOptional<std::string> nca_titlekey;
|
||||||
sOptional<std::string> nca_bodykey;
|
sOptional<std::string> nca_bodykey;
|
||||||
|
sOptional<std::string> ticket_path;
|
||||||
|
sOptional<std::string> cert_path;
|
||||||
sOptional<std::string> part0_path;
|
sOptional<std::string> part0_path;
|
||||||
sOptional<std::string> part1_path;
|
sOptional<std::string> part1_path;
|
||||||
sOptional<std::string> part2_path;
|
sOptional<std::string> part2_path;
|
||||||
|
@ -94,6 +100,8 @@ private:
|
||||||
sOptional<std::string> mAssetIconPath;
|
sOptional<std::string> mAssetIconPath;
|
||||||
sOptional<std::string> mAssetNacpPath;
|
sOptional<std::string> mAssetNacpPath;
|
||||||
|
|
||||||
|
fnd::List<pki::SignedData<pki::CertificateBody>> mCertChain;
|
||||||
|
|
||||||
bool mListApi;
|
bool mListApi;
|
||||||
bool mListSymbols;
|
bool mListSymbols;
|
||||||
nx::npdm::InstructionType mInstructionType;
|
nx::npdm::InstructionType mInstructionType;
|
||||||
|
@ -107,5 +115,7 @@ private:
|
||||||
bool determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) const;
|
bool determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||||
bool determineValidCnmtFromSample(const fnd::Vec<byte_t>& sample) const;
|
bool determineValidCnmtFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||||
bool determineValidNacpFromSample(const fnd::Vec<byte_t>& sample) const;
|
bool determineValidNacpFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||||
|
bool determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||||
|
bool determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||||
nx::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
|
nx::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
|
||||||
};
|
};
|
|
@ -11,6 +11,8 @@
|
||||||
#include "NsoProcess.h"
|
#include "NsoProcess.h"
|
||||||
#include "NroProcess.h"
|
#include "NroProcess.h"
|
||||||
#include "NacpProcess.h"
|
#include "NacpProcess.h"
|
||||||
|
#include "PkiCertProcess.h"
|
||||||
|
#include "EsTikProcess.h"
|
||||||
#include "AssetProcess.h"
|
#include "AssetProcess.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -173,6 +175,29 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
nacp.process();
|
nacp.process();
|
||||||
}
|
}
|
||||||
|
else if (user_set.getFileType() == FILE_PKI_CERT)
|
||||||
|
{
|
||||||
|
PkiCertProcess cert;
|
||||||
|
|
||||||
|
cert.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||||
|
cert.setKeyset(&user_set.getKeyset());
|
||||||
|
cert.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
|
cert.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
cert.process();
|
||||||
|
}
|
||||||
|
else if (user_set.getFileType() == FILE_ES_TIK)
|
||||||
|
{
|
||||||
|
EsTikProcess tik;
|
||||||
|
|
||||||
|
tik.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||||
|
tik.setKeyset(&user_set.getKeyset());
|
||||||
|
tik.setCertificateChain(user_set.getCertificateChain());
|
||||||
|
tik.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
|
tik.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
tik.process();
|
||||||
|
}
|
||||||
else if (user_set.getFileType() == FILE_HB_ASSET)
|
else if (user_set.getFileType() == FILE_HB_ASSET)
|
||||||
{
|
{
|
||||||
AssetProcess obj;
|
AssetProcess obj;
|
||||||
|
|
|
@ -27,6 +27,8 @@ enum FileType
|
||||||
FILE_NSO,
|
FILE_NSO,
|
||||||
FILE_NRO,
|
FILE_NRO,
|
||||||
FILE_NACP,
|
FILE_NACP,
|
||||||
|
FILE_PKI_CERT,
|
||||||
|
FILE_ES_TIK,
|
||||||
FILE_HB_ASSET,
|
FILE_HB_ASSET,
|
||||||
FILE_INVALID = -1,
|
FILE_INVALID = -1,
|
||||||
};
|
};
|
||||||
|
@ -62,7 +64,6 @@ struct sOptional
|
||||||
struct sKeyset
|
struct sKeyset
|
||||||
{
|
{
|
||||||
crypto::rsa::sRsa2048Key acid_sign_key;
|
crypto::rsa::sRsa2048Key acid_sign_key;
|
||||||
|
|
||||||
crypto::aes::sAes128Key package1_key[kMasterKeyNum];
|
crypto::aes::sAes128Key package1_key[kMasterKeyNum];
|
||||||
crypto::rsa::sRsa2048Key package2_sign_key;
|
crypto::rsa::sRsa2048Key package2_sign_key;
|
||||||
crypto::aes::sAes128Key package2_key[kMasterKeyNum];
|
crypto::aes::sAes128Key package2_key[kMasterKeyNum];
|
||||||
|
@ -90,6 +91,11 @@ struct sKeyset
|
||||||
crypto::rsa::sRsa2048Key sign_key;
|
crypto::rsa::sRsa2048Key sign_key;
|
||||||
crypto::aes::sAes128Key titlekey_kek[kMasterKeyNum];
|
crypto::aes::sAes128Key titlekey_kek[kMasterKeyNum];
|
||||||
} ticket;
|
} ticket;
|
||||||
|
|
||||||
|
struct sPkiData
|
||||||
|
{
|
||||||
|
crypto::rsa::sRsa4096Key root_sign_key;
|
||||||
|
} pki;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline byte_t charToByte(char chr)
|
inline byte_t charToByte(char chr)
|
||||||
|
|
Loading…
Reference in a new issue