Secure Monitor
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 |