Secure Monitor

From Nintendo Switch Brew
Revision as of 04:51, 13 March 2018 by SciresM (talk | contribs) (better)
Jump to navigation Jump to search

Secure Monitor Calls

The secure monitor provides two top level handlers of which each provides a range of sub handlers.

Secure Monitor Calls follow the ARM SMC calling convention up to a small change:

Bit number Bit mask Description
31 0x80000000 Set to 0 means Yielding Call; Set to 1 means Fast Call.
30 0x40000000 Set to 0 means SMC32 convention; Set to 1 means SMC64.
29-24 0x3F000000 Service Call ranges.
23-16 0x00FF0000 Must be zero.
15-8 0x0000FF00 Argument type. This is different from the ARM SMC calling convention.
7-0 0x000000FF Function number within the range call type.

If bit n is set in the argument type then parameter Xn is treated as a pointer and the kernel will setup address translation for it in svcCallSecureMonitor.

SMC arguments are passed using registers X0-X7 with X0 always sending the call sub-id and returning the result of the call.

ID 0

Functions exposed to user-mode processes using svcCallSecureMonitor.

Sub-ID Name In Out
0xC3000401 SetConfig
0xC3000002 GetConfig (Same as ID 1, Sub-ID 4)
0xC3000003 CheckStatus
0xC3000404 GetResult
0xC3000E05 ExpMod
0xC3000006 GetRandomBytes (Same as ID 1, Sub-ID 5)
0xC3000007 #GenerateAesKek
0xC3000008 #LoadAesKey
0xC3000009 #CryptAes
0xC300000A #GenerateSpecificAesKey
0xC300040B #ComputeCmac
[1.0.0-4.1.0] 0xC300100C #LoadRsaOaepKey
[5.0.0+] 0xC300D60C #EncryptRsaKeyForImport
[1.0.0-4.1.0] 0xC300100D #DecryptRsaPrivateKey
[5.0.0] 0xC300100D #DecryptOrImportRsaKey
[1.0.0-4.1.0] 0xC300100E #LoadSecureExpModKey
0xC300060F #SecureExpMod
0xC3000610 #UnwrapRsaOaepWrappedTitleKey
0xC3000011 #LoadTitleKey
0xC3000012 [2.0.0+] UnwrapAesWrappedTitleKey

The overall concept here is the following:

  • All key material (AES and RSA) is stored in userspace, but it's encrypted with random AES kek's ("key encryption keys").
  • Each kek is generated as a function of an access key (picked at random).
  • The kek is generated differently depending on the #CryptoUsecase the key is used for.
    • This means: Each key is "locked" to the #CryptoUsecase it was designated for.
    • You can use a key for a different usecase, but you will only get garbage output.
  • After the kek has been generated, it is wrapped with a session-specific key and given back to userspace.
    • This means: Plaintext kek keys never leave TrustZone.
    • Further, this means: Actual AES/RSA keys never leave TrustZone.

Note: The CryptoUsecase_TitleKey represents a RSA wrapped AES key.

GenerateAesKek

Takes an "access key" as input, an #CryptoUsecase.

Returns a session-unique kek for said usecase.

LoadAesKey

Takes a session kek created with #GenerateAesKek, and a wrapped AES key.

The session kek must have been created with CryptoUsecase_Aes.

CryptAes

Encrypts/decrypts using Aes (CTR and CBC).

Key must be set prior using one of the #LoadAesKey, #GenerateSpecificAesKey or #LoadRsaWrappedAesKey commands.

GenerateSpecificAesKey

Todo: This one seems unrelated to #CryptoUsecase.

LoadRsaOaepKey

Takes a session kek created with #GenerateAesKek, a wrapped AES key, and a wrapped RSA private key.

The session kek must have been created with CryptoUsecase_RsaOaep.

This function was removed in 5.0.0, and replaced with #EncryptRsaKeyForImport.

EncryptRsaKeyForImport

Takes in two session keks created with #GenerateAesKek, two wrapped AES keys, an enum member, and a wrapped RSA private key.

Decrypts and validates the wrapped RSA private key with the first kek/wrapped key, and re-encrypts it with the second if valid.

The re-encrypted key is then passed to the user, for use with #DecryptOrImportRsaKey.

DecryptRsaPrivateKey

Takes a session kek created with #GenerateAesKek, a wrapped AES key, an enum member, and a wrapped RSA private key.

The session kek must have been created with CryptoUsecase_RsaPrivate.

[4.0.0+] The SMC handler when certain conditions pass and SMC_ID==0xC300100D now returns error 0x6 instead of calling the handler funcptr.

DecryptOrImportRsaKey

This function replaced #DecryptRsaPrivateKey in 5.0.0, adding an additional enum member argument.

This SMC extends DecryptRsaPrivateKey's original functionality to enable importing private keys into the security engine instead of decrypting them, when certain enum members are passed.

LoadSecureExpModKey

Takes a session kek created with #GenerateAesKek, and a wrapped RSA key.

The session kek must have been created with CryptoUsecase_RsaSecureExpMod.

This function was removed in 5.0.0, and replaced with #EncryptRsaKeyForImport.

SecureExpMod

Performs an Exp Mod operation using an exponent previously loaded with the #LoadSecureExpModKey command.

UnwrapRsaOaepWrappedTitleKey

Takes an Rsa-Oaep-wrapped TitleKey, an RSA Public Key, and a label hash.

Performs an Exp Mod operation using an exponent previously loaded with the #LoadRsaOaepKey command, and then validates/extracts a Titlekey from the resulting message.

Returns a session-unique AES key especially for use in #LoadTitleKey.

LoadTitleKey

Takes a session-unique AES key from #UnwrapAesWrappedTitleKey or #UnwrapRsaOaepWrappedTitleKey.

enum CryptoUsecase

Value Name
0 CryptoUsecase_Aes
1 CryptoUsecase_RsaPrivate
2 CryptoUsecase_RsaSecureExpMod
3 CryptoUsecase_RsaOaep

ID 1

Functions exposed to the kernel internally.

Sub-ID Name In Out
0xC4000001 #CpuSuspend X1=power_state, X2=entrypoint_addr, X3=context_id None
0x84000002 #CpuOff None None
0xC4000003 #CpuOn X1=target_cpu, X2=entrypoint_addr, X3=context_id, X4,X5,X6,X7=0 X0=result
0xC3000004 #GetConfig (Same as ID 0, Sub-ID 2) W1=config_item, X2,X3,X4,X5,X6,X7=0 X0=result, X1,X2,X3,X4=config_val
0xC3000005 #GetRandomBytes (Same as ID 0, Sub-ID 6) X1=size, X2,X3,X4,X5,X6,X7=0 X0=result, X1,X2,X3,X4,X5,X6,X7=rand_bytes
0xC3000006 #Panic W1=panic_color, X2,X3,X4,X5,X6,X7=0 X0=result
0xC3000007 [2.0.0+] #ProtectKernelRegion X1=carveout_index, X2=region_phys_addr, X3=region_size, X4,X5,X6,X7=0 X0=result
0xC3000008 [2.0.0+] #ReadWriteRegister X1=reg_addr, W2=rw_mask, W3=in_val, X4,X5,X6,X7=0 X0=result, W1=out_val

CpuSuspend

Standard ARM PCSI SMC. Suspends the CPU (CPU0).

The kernel calls this SMC on shutdown with power_state set to 0x0201001B (power level: 0x02==system; power type: 0x01==powerdown; ID: 0x1B).

CpuOff

Standard ARM PCSI SMC. Turns off the CPU (CPU1, CPU2 or CPU3).

CpuOn

Standard ARM PCSI SMC. Turns on the CPU (CPU1, CPU2 or CPU3).

GetConfig

Takes a config_item and returns an associated config_val.

GetRandomBytes

Takes a size and returns rand_bytes.

The kernel limits size to 0x38 (for fitting in return registers).

Panic

Issues a system panic.

The kernel always calls this with panic_color set to 0xF00.

ProtectKernelRegion

Configures memory controller carveout regions.

If carveout_index is 0, region_phys_addr and region_size are used to configure MC_SECURITY_CARVEOUT4. If carveout_index is 1, region_phys_addr and region_size are used to configure MC_SECURITY_CARVEOUT5. Any other carveout_index values are invalid.

The kernel calls this with carveout_index set to 0, region_phys_addr set to 0x80060000 and region_size set to a dynamically calculated size which covers all the kernel and built-in sysmodules' DRAM regions.

ReadWriteRegister

Relays svcReadWriteRegister to the Secure Monitor.

Errors

Value Description
2 Invalid input
3 Busy