1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-09-18 21:13:25 +01:00

Some small changes.

* tik: check for common certificate availability before attempting to convert a personalized ticket to a common one. The raw common certificate chain data for the ticket signature issuer is now returned.

* usb: skip waitMulti call in the USB background thread if an invalid endpoint max packet size was received from the USB host in the previous while loop iteration.
This commit is contained in:
Pablo Curiel 2020-08-27 15:18:31 -04:00
parent 971d7fd72c
commit 679aa170b5
4 changed files with 60 additions and 21 deletions

View file

@ -121,7 +121,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam
return true;
}
void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik)
bool tikConvertPersonalizedTicketToCommonTicket(Ticket *tik, u8 **out_raw_cert_chain, u64 *out_raw_cert_chain_size)
{
TikCommonBlock *tik_common_block = NULL;
@ -130,9 +130,34 @@ void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik)
u64 signature_size = 0;
bool dev_cert = false;
char cert_chain_issuer[0x40] = {0};
static const char *common_cert_names[] = { "XS00000020", "XS00000022", NULL };
u8 *raw_cert_chain = NULL;
u64 raw_cert_chain_size = 0;
if (!tik || tik->type == TikType_None || tik->type > TikType_SigHmac160 || tik->size < SIGNED_TIK_MIN_SIZE || tik->size > SIGNED_TIK_MAX_SIZE || \
!(tik_common_block = tikGetCommonBlock(tik->data)) || tik_common_block->titlekey_type != TikTitleKeyType_Personalized) return;
!(tik_common_block = tikGetCommonBlock(tik->data)) || tik_common_block->titlekey_type != TikTitleKeyType_Personalized || !out_raw_cert_chain || !out_raw_cert_chain_size)
{
LOGFILE("Invalid parameters!");
return false;
}
/* Generate raw certificate chain for the new signature issuer (common). */
dev_cert = (strstr(tik_common_block->issuer, "CA00000004") != NULL);
for(u8 i = 0; common_cert_names[i] != NULL; i++)
{
sprintf(cert_chain_issuer, "Root-CA%08X-%s", dev_cert ? 4 : 3, common_cert_names[i]);
raw_cert_chain = certGenerateRawCertificateChainBySignatureIssuer(cert_chain_issuer, &raw_cert_chain_size);
if (raw_cert_chain) break;
}
if (!raw_cert_chain)
{
LOGFILE("Failed to generate raw certificate chain for common ticket signature issuer!");
return false;
}
/* Wipe signature. */
sig_type = signatureGetSigType(tik->data, false);
@ -141,9 +166,8 @@ void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik)
memset(signature, 0xFF, signature_size);
/* Change signature issuer. */
dev_cert = (strstr(tik_common_block->issuer, "CA00000004") != NULL);
memset(tik_common_block->issuer, 0, sizeof(tik_common_block->issuer));
sprintf(tik_common_block->issuer, "Root-CA%08X-XS00000020", (dev_cert ? 4 : 3));
sprintf(tik_common_block->issuer, "%s", cert_chain_issuer);
/* Wipe the titlekey block and copy the titlekek-encrypted titlekey to it. */
memset(tik_common_block->titlekey_block, 0, sizeof(tik_common_block->titlekey_block));
@ -164,6 +188,12 @@ void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik)
tik_common_block->sect_hdr_entry_size = 0;
memset(tik->data + tik->size, 0, SIGNED_TIK_MAX_SIZE - tik->size);
/* Update output pointers. */
*out_raw_cert_chain = raw_cert_chain;
*out_raw_cert_chain_size = raw_cert_chain_size;
return true;
}
static bool tikRetrieveTicketFromGameCardByRightsId(Ticket *dst, const FsRightsId *id)

View file

@ -173,9 +173,10 @@ typedef struct {
/// Titlekey is also RSA-OAEP unwrapped (if needed) and titlekek decrypted right away.
bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gamecard);
/// This will convert a TikTitleKeyType_Personalized ticket into a TikTitleKeyType_Common ticket.
/// Converts a TikTitleKeyType_Personalized ticket into a TikTitleKeyType_Common ticket and generates a raw certificate chain for the new signature issuer.
/// Bear in mind the 'size' member from the Ticket parameter will be updated by this function to remove any possible references to ESV1/ESV2 records.
void tikConvertPersonalizedTicketToCommonTicket(Ticket *tik);
/// Raw certificate chain data will be saved to the provided pointers. certGenerateRawCertificateChainBySignatureIssuer() is used internally, so the output buffer must be freed by the user.
bool tikConvertPersonalizedTicketToCommonTicket(Ticket *tik, u8 **out_raw_cert_chain, u64 *out_raw_cert_chain_size);
/// Helper inline functions.

View file

@ -431,6 +431,7 @@ static void usbDetectionThreadFunc(void *arg)
Result rc = 0;
int idx = 0;
bool skip_wait = false;
Waiter usb_change_event_waiter = waiterForEvent(g_usbStateChangeEvent);
Waiter usb_timeout_event_waiter = waiterForUEvent(&g_usbTimeoutEvent);
@ -438,9 +439,12 @@ static void usbDetectionThreadFunc(void *arg)
while(true)
{
/* Wait until an event is triggered. */
rc = waitMulti(&idx, -1, usb_change_event_waiter, usb_timeout_event_waiter, exit_event_waiter);
if (R_FAILED(rc)) continue;
if (!skip_wait)
{
/* Wait until an event is triggered. */
rc = waitMulti(&idx, -1, usb_change_event_waiter, usb_timeout_event_waiter, exit_event_waiter);
if (R_FAILED(rc)) continue;
}
rwlockWriteLock(&g_usbDeviceLock);
rwlockWriteLock(&(g_usbDeviceInterface.lock));
@ -451,7 +455,7 @@ static void usbDetectionThreadFunc(void *arg)
/* Retrieve current USB connection status. */
/* Only proceed if we're dealing with a status change. */
g_usbHostAvailable = usbIsHostAvailable();
g_usbSessionStarted = false;
g_usbSessionStarted = skip_wait = false;
g_usbTransferRemainingSize = g_usbTransferWrittenSize = 0;
g_usbEndpointMaxPacketSize = 0;
@ -463,13 +467,18 @@ static void usbDetectionThreadFunc(void *arg)
if (g_usbHostAvailable)
{
/* Wait until a session is established. */
/* If the session is successfully established, then we'll get the endpoint max packet size from the data chunk sent by the USB host. */
/* This is done to accurately know when and where to enable Zero Length Termination (ZLT) packets during bulk transfers. */
/* As much as I'd like to avoid this, usb:ds doesn't disclose information such as the exact device descriptor and/or speed used by the USB host. */
g_usbSessionStarted = (usbStartSession() && usbGetMaxPacketSizeFromHost());
/* Check if the exit event was triggered while waiting for a session to be established. */
if (!g_usbSessionStarted && g_usbDetectionThreadExitFlag) break;
g_usbSessionStarted = usbStartSession();
if (g_usbSessionStarted)
{
/* Get the endpoint max packet size from the response sent by the USB host. */
/* This is done to accurately know when and where to enable Zero Length Termination (ZLT) packets during bulk transfers. */
/* As much as I'd like to avoid this, usb:ds doesn't disclose information such as the exact device descriptor and/or speed used by the USB host. */
/* If this step fails (e.g. unexpected max packet size), the write endpoint will be stalled and we'll wait until a new USB session is established. */
if (!(skip_wait = !usbGetMaxPacketSizeFromHost())) LOGFILE("USB session successfully established. Endpoint max packet size: 0x%04X.", g_usbEndpointMaxPacketSize);
} else {
/* Check if the exit event was triggered while waiting for a session to be established. */
if (g_usbDetectionThreadExitFlag) break;
}
}
rwlockWriteUnlock(&(g_usbDeviceInterface.lock));
@ -545,14 +554,13 @@ static bool usbGetMaxPacketSizeFromHost(void)
usbDsEndpoint_Stall(g_usbDeviceInterface.endpoint_in);
rwlockWriteUnlock(&(g_usbDeviceInterface.lock_in));
/* Reset endpoint max packet size. */
/* Reset flags. */
g_usbSessionStarted = false;
g_usbEndpointMaxPacketSize = 0;
return false;
}
LOGFILE("USB session successfully established. Endpoint max packet size: 0x%04X.", g_usbEndpointMaxPacketSize);
return true;
}

View file

@ -4,7 +4,7 @@ todo:
nca: function to write re-encrypted nca headers / nca fs headers (don't forget nca0 please)
nca: function to patch the private npdm acid signature from a program nca + patch the acid signature from the nca header
tik: make sure the common crypto cert (XS20, XS22) is available when fakesigning a ticket
tik: option to wipe elicense property mask
tik: automatically dump tickets to the SD card?
tik: use dumped tickets when the original ones can't be found in the ES savefile?