Secure Kernel Calls

From N64brew Wiki
Jump to navigation Jump to search

This page is relevant only for the iQue Player, not the original Nintendo 64. If you're an N64 developer, this page isn't useful to you.

Secure Kernel Calls (or SKCs) are the mechanism through which application software, such as games or the iQue Menu, can communicate with the Secure Kernel. SKCs are called like any other function, following the MIPS C ABI. On the application side, they are implemented as stubs linked as part of the ROM.

The mechanism

An application runs an SKC by calling the relevant stub function. Each stub is a small chunk of code that loads the number of the SKC to call into $v0, then triggers a Secure Kernel trap by reading from MI_BB_SECURE_EXCEPTION. SKCs are implemented in the Secure Kernel as regular C functions, and the SKC handler passes through the argument registers unchanged, so these stubs help to ensure that the CPU registers contain the correct parameters. All known SKCs return an int32_t; 0 on success, and <0 on error. Patched or custom SKs may return >0 for non-original errors.

Types used in Secure Kernel Calls

Ticket bundle

Ticket bundle[1]
Offset C type Name Description
0x00 Ticket *[2][3] ticket A pointer to an iQue Player ticket structure.
0x04 Certificate *[5][4] ticketCerts An array of 5 pointers to content certificates; this must be a valid certificate chain, such that the first certificate signs the ticket, the second certificate signs the first certificate, etc., until a certificate is signed by Root. Unused certificate slots should be set to NULL.
0x18 Certificate *[5][4] cmdCerts An array of 5 pointers to content certificates; this must also be a valid certificate chain, but that signs the ticket's embedded CMD structure.

The ticket structure contains all of the information needed for SK to set up the encryption hardware to decrypt the application to be launched. SK ensures that the ticket and its included CMD[5][6] are signed by iQue, as the CMD contains the SHA-1 hash of the application to be launched.

Launch CRLs

Launch CRLs[7]
Offset C type Name Description
0x00 CRL bundle[7] ticketRL A Certificate Revocation List bundle for revoking certificates that sign tickets.
0x1C CRL bundle[7] certRL A Certificate Revocation List bundle for revoking certificates that sign other certificates.
0x38 CRL bundle[7] cmdRL A Certificate Revocation List bundle for revoking certificates that sign CMD structures.

These 3 revocation lists are used when ensuring the ticket provided to SK is signed, so that iQue can revoke any certificates used to sign content that should no longer be accepted.

Recrypt list

Recrypt list[7][8]
Offset C type Name Description
0x00 ECC signature[9] sig An ECC signature (using the console's ECC private key and the identity 0x06091968[10], presumably a significant date for one of the developers) over the following data.
0x40 uint32_t entries The number of entries in the list.
0x44 Recrypt entry[entries] list An array of recrypt entries. Each entry contains the recrypt key and state for one piece of content on the console.

The data provided to SK here usually comes directly from recrypt.sys on the iQue Player's NAND. It may be modified as part of an SKC, and as such it gets written back to the file after the call.


These are the SKCs found in the SK version on all known consoles.

Retail SKCs
Number Name
0 skGetId
1 skLaunchSetup
2 skLaunch
3 skRecryptListValid
4 skRecryptBegin
5 skRecryptData
6 skRecryptComputeState
7 skRecryptEnd
8 skSignHash
9 skVerifyHash
10 skGetConsumption
11 skAdvanceTicketWindow
12 skSetLimit
13 skExit
14 skKeepAlive


skGetId(uint32_t * bbid_out)

Retrieves the console's unique BBID. Always returns 0.


skLaunchSetup(Ticket bundle * bundle, Launch CRLs * crls, Recrypt list * list)

Prepares SK for launching an application. The ticket and CMD in the bundle are copied to internal memory, the keys are decrypted, and the encryption hardware is prepared with the AES key and IV. Returns various negative numbers to indicate errors, e.g. the application needs to be recrypted.


skLaunch(void * address)

Launches the application, by first performing some verification on the contents, then jumping to the provided address. This requires that the entrypoint has already been loaded to the correct place in memory and that all the hardware has been set up correctly. Returns -1 on error, including if the application returns, which should not be possible under normal circumstances.


skRecryptListValid(Recrypt list * list)

Verifies that the provided recrypt list is valid, i.e. that it's a valid size and that the signature is correct. Returns -1 if the list is invalid.


skRecryptBegin(Ticket bundle * bundle, Launch CRLs * crls, Recrypt list * list)

Prepares SK for recrypting an application. The ticket in the bundle is verified, the recrypt list is searched for an existing entry, one is made if none exists, the encryption hardware is configured, and SK prepares for performing a SHA-1 hash. Returns a subset of what skLaunchSetup returns.


skRecryptData(void * data, uint32_t size)

Recrypts the provided data, using the previously set context. Returns -1 if the data pointer is invalid.


skRecryptComputeState(void * data, uint32_t size)

Due to how AES-CBC works, in order to recover a partially-completed recryption, the last chunk of data that was successfully recrypted must be provided (non-recrypted) to set up the context prior to recrypting any new data. The last 16 bytes of data provided with this function are copied to SK's recrypt context.


skRecryptEnd(Recrypt list * list)

Notifies SK that the recryption is complete. SK updates the recrypt list to indicate that the relevant entry has been fully recrypted, and checks to see if the SHA-1 hash it calculated while recrypting the data matches the hash in the ticket provided in skRecryptBegin. Returns -1 if any error occurs, e.g. if the hash does not match.


skSignHash(SHA-1 hash[11] * hash, ECC signature[9] * sig_out)

Signs the given SHA-1 hash using the console's ECC private key and the identity 1 (note: not the same identity as is used for signing recrypt.sys, so signatures are not compatible between the two). This is used by the iQue Menu to sign save data, although nothing happens if the signature doesn't match when loading the save data. Returns -1 if the hash or signature pointers are invalid.


skVerifyHash(SHA-1 hash * hash, Signature[12] * sig, Certificate ** cert_chain, Launch CRLs * crls)

Verifies that the provided hash matches the provided signature. This call supports all of the signature types on the iQue Player (ECC, RSA2048, RSA4096), and so it takes a pointer to a generic signature[12], rather than a specific signature type. The certificate chain and CRLs are used for RSA2048 and RSA4096 signatures, and follow the same format as in a ticket bundle (i.e. the certificate chain has a maximum length of 5, and shorter chains must be NULL-terminated). Returns various negative numbers for various errors; most errors are represented by -1, but trying to use revoked certificates returns -9, for example.


skGetConsumption(uint16_t * window, uint16_t * counter)

Retrieves the consumption counters for all currently-tracked applications and the TID window. The TID window stores the first ticket ID for which the consumption is being tracked; the consumption counter refers to the number of minutes that have been played of a given application, which is recorded when the ticket specifies that the application is a time-limited trial. This data is stored in Virage0/1[13][14]. Returns -1 if the consumption counter pointer is invalid.



Shifts all consumption counters down to the previous slot, deleting the first counter, and increments the TID window. Since iQue published such a small number of titles during the console's lifespan (just 14 released games), it's unknown whether this SKC has ever been called in a non-test environment. Returns -1 if writing to Virage0/1 fails.


skSetLimit(uint16_t limit, uint16_t limit_type)

Overrides the trial limit and trial type stored in the currently-loaded ticket. Unknown purpose in practice. Returns -1 if no ticket is currently loaded.



Exits the application immediately, by jumping to SK's entrypoint. Should never return, but returns 0 unconditionally if exiting somehow fails.



When running trial applications, the secure timer triggers a Secure Kernel trap at regular intervals. If the time since the last time this SKC was called is too large, the application is forcefully exited by jumping to SK's entrypoint. This SKC, therefore, updates the variable used to track the last time this call was made. If the call returns, it unconditionally returns 0; however, the timer is also checked during the call, and so it can exit forcefully by jumping to SK's entrypoint instead.

Debug calls

These are the SKCs known to have existed in debug versions of SK at some point, but for which the operation and function signatures are not known.

Debug SKCs
Number Name
15 skGetRandomKeyData
16 skDumpVirage
17 skTest2
18 skTest3
19 skResetWindow
20 skValidateRls


  1. decompals, iQuePlayer-SecureKernel, BbTicketBundle
  2. decompals, iQuePlayer-SecureKernel, BbTicket
  3. iQueBrew, "Ticket"
  4. 4.0 4.1 decompals, iQuePlayer-SecureKernel, BbCertBase
  5. decompals, iQuePlayer-SecureKernel, BbContentMetaData
  6. iQueBrew, "CMD"
  7. 7.0 7.1 7.2 7.3 7.4 decompals, iQuePlayer-SecureKernel, BbAppLaunchCrls
  8. iQueBrew, "Recrypt.sys"
  9. 9.0 9.1 decompals, iQuePlayer-SecureKernel, BbEccSig
  10. decompals, iQuePlayer-SecureKernel
  11. decompals, iQuePlayer-SecureKernel, BbShaHash
  12. 12.0 12.1 decompals, iQuePlayer-SecureKernel, BbGenericSig
  13. decompals, iQuePlayer-SecureKernel, BbVirage01
  14. iQueBrew, "Virage0-1"