Difference between revisions of "OTP Registers"

From 3dbrew
Jump to navigation Jump to search
(Wrong size fixed)
 
(17 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Console-unique keys seem to be derived from here, though it is unknown how. Access to this region is disabled once the ARM9 writes 0x2 to [[CONFIG|REG_SYSPROT9]].
+
This region (0x10012000-0x10012100) is used as persistent storage on SoC and for passing the TWL console ID around (0x10012100-0x10012108).
  
This is very likely the console-unique data store, including [[CTCert]] and other unit info values, that ends up in ITCM at 0x01FFB800. Bootrom would decrypt it, check for magic (0xDEADB00F), and then set CFG_UNITINFO, etc to match the specific console at hand. This is a guess based on the matching size of both sets of data (ITCM's is padded to 0x100, specifically) and the lack of another known source for this data on the system (it is not sourced from eMMC). On top of this, the latter half of this data is likely used as console-unique keydata, thus explaining ITCM's copy being memcleared and the OTP lock mechanism existing. 
+
== Overview ==
  
On [[FIRM]] versions prior to 2.32-15 ([[3.0.0-6|3.0.0-X]]), title version v5647 dated Tue, 06 Dec 11 20:58:59 -0600, this region was left unprotected. On versions since 2.32-15 ([[3.0.0-6|3.0.0-X]]), title version v5647 dated Tue, 06 Dec 11 20:58:59 -0600 this has been fixed, and the region disable is now done by Kernel9 after doing console-unique TWL keyinit, by setting bit 1 of [[CONFIG|REG_SYSPROT9]]. However, with the [[New_3DS]] FIRM ARM9 binary this is now done in the [[FIRM]] ARM9 binary loader, which also uses the 0x10012000 region for New 3DS key generation.
+
Console-unique keys are derived from here. Access to this region is disabled once the ARM9 writes 0x2 to [[CONFIG|REG_SYSPROT9]].
  
On development units ([[CONFIG|UNITINFO]]!=0) ARM9 uses the first 8-bytes from 0x10012000 for the TWL Console ID. This region doesn't seem to be used by NATIVE_FIRM on retail at all, besides New3DS key-generation in the [[FIRM|ARM9-loader]]. It is unknown if bootrom reads from it, but it is likely.
+
This is the console-unique data store, including [[CTCert]] etc, that ends up in ITCM at 0x01FFB800. After decryption, the first 0x90-bytes of plaintext are copied to 0x01FFB800 if hash verification passes. Refer to [[Memory_layout#ARM9_ITCM]] for what is contained in the decrypted OTP.
 +
 
 +
On [[FIRM]] versions prior to [[3.0.0-6|3.0.0-X]], this region was left unprotected. On versions since [[3.0.0-6|3.0.0-X]], this has been fixed, and the region disable is now done by Kernel9 after doing console-unique TWL keyinit, by setting bit 1 of [[CONFIG|REG_SYSPROT9]]. However, with the [[New_3DS]] FIRM ARM9 binary this is now done in the [[FIRM]] ARM9 binary loader, which also uses the 0x10012000 region for New 3DS key generation.
 +
 
 +
On development units ([[CONFIG|UNITINFO]] != 0) ARM9 uses the first 8-bytes from 0x10012000 for the TWL Console ID. This region doesn't seem to be used by NATIVE_FIRM on retail at all, besides New3DS key-generation in the [[FIRM|ARM9-loader]].
 +
 
 +
Normally [[Bootloader|Boot9]] will pass plaintext_otp+0x90 to the AES keyinit function, but when hash verification fails it will pass 0x10012000(otp+0) instead.
 +
 
 +
== Sections ==
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 14: Line 22:
 
| 0x0
 
| 0x0
 
| 0x100
 
| 0x100
| Console-unique data. This data appears to be random, even when multiple consoles' dumps from this area are XORed. None of the raw data here seems to match any of the console-unique keys (tested: keyX, keyY and normal-key, both big and little u32 endianness for all keyslots) for the AES engine. It's unknown whether there's any encryption on this area.
+
| Console-unique data encrypted with AES-CBC. The normalkey and IV are stored in Boot9(retail/devunit have seperate normalkey+IV for this). The last 0x20-bytes of plaintext are a SHA256 hash over the first 0xE0-bytes of plaintext.
 
|-
 
|-
 
| 0x100
 
| 0x100
 
| 0x8
 
| 0x8
 
| Before writing REG_SYSPROT9 bit1, the ARM9 copies the 8-byte TWL Console ID here. This sets the registers at 0x4004D00 for ARM7.
 
| Before writing REG_SYSPROT9 bit1, the ARM9 copies the 8-byte TWL Console ID here. This sets the registers at 0x4004D00 for ARM7.
 +
|}
 +
 +
== Plaintext OTP ==
 +
{| class="wikitable" border="1"
 +
!  Offset
 +
!  Size
 +
!  Description
 +
|-
 +
| 0x0
 +
| 0x4
 +
| This is always 0xDEADB00F.
 +
|-
 +
| 0x4
 +
| 0x4
 +
| This is the u32 DeviceId.
 +
|-
 +
| 0x8
 +
| 0x10
 +
| This is the fall-back keyY used for movable.sed keyY when movable.sed doesn't exist in NAND(the first two words here are used on retail for generating console-unique TWL keydata/etc). This is also used for "LocalFriendCodeSeed", etc.
 +
|-
 +
| 0x18
 +
| 0x1
 +
| OTP version
 +
|-
 +
| 0x19
 +
| 0x1
 +
| This determines if the OTP is for a dev system; it indicates the [[CTCert]] issuer type: 0 = retail "Nintendo CA - G3_NintendoCTR2prod", non-zero = dev "Nintendo CA - G3_NintendoCTR2dev".
 +
|-
 +
| 0x1A
 +
| 0x6
 +
| Manufacturing date (of the SoC?). Usually month(s) before the dates in the logs stored in [[Flash_Filesystem|TWLNAND]]. Each byte is one field: year, month, day, hour, minute, second. Year is encoded as year-1900 so that it fits in one byte. This order matches up with the layout of a <code>struct tm</code>.
 +
|-
 +
| 0x20
 +
| 0x4
 +
| This is the CTCert expiry time as UNIX timestamp, this is specified in big endian if the OTP version is <5.
 +
|-
 +
| 0x24
 +
| 0x20
 +
| This is the CTCert ECDSA privk.
 +
|-
 +
| 0x44
 +
| 0x3C
 +
| This is the CTCert ECDSA signature (sect233r1?/SHA-256).
 +
|-
 +
| 0x80
 +
| 0x10
 +
| This is all-zero.
 +
|-
 +
| 0x90
 +
| 0x50
 +
| Used by Boot9 for generating the console-unique AES [[AES_Registers|keyXs]]. However, due to a bug(?) in Boot9, only the first 0x1C-bytes here actually affect console-unique key generation. The rest of the data is used for hashing, but that output hash only gets overwritten without being used afterwards.
 +
 +
Note that the size passed to the Boot9 keyinit code for console-unique-buffer-size is 0x70, hence this includes the below OTP hash.
 +
|-
 +
| 0xE0
 +
| 0x20
 +
| SHA256 hash over the previous 0xE0-bytes.
 
|}
 
|}

Latest revision as of 14:18, 21 November 2024

This region (0x10012000-0x10012100) is used as persistent storage on SoC and for passing the TWL console ID around (0x10012100-0x10012108).

Overview[edit]

Console-unique keys are derived from here. Access to this region is disabled once the ARM9 writes 0x2 to REG_SYSPROT9.

This is the console-unique data store, including CTCert etc, that ends up in ITCM at 0x01FFB800. After decryption, the first 0x90-bytes of plaintext are copied to 0x01FFB800 if hash verification passes. Refer to Memory_layout#ARM9_ITCM for what is contained in the decrypted OTP.

On FIRM versions prior to 3.0.0-X, this region was left unprotected. On versions since 3.0.0-X, this has been fixed, and the region disable is now done by Kernel9 after doing console-unique TWL keyinit, by setting bit 1 of REG_SYSPROT9. However, with the New_3DS FIRM ARM9 binary this is now done in the FIRM ARM9 binary loader, which also uses the 0x10012000 region for New 3DS key generation.

On development units (UNITINFO != 0) ARM9 uses the first 8-bytes from 0x10012000 for the TWL Console ID. This region doesn't seem to be used by NATIVE_FIRM on retail at all, besides New3DS key-generation in the ARM9-loader.

Normally Boot9 will pass plaintext_otp+0x90 to the AES keyinit function, but when hash verification fails it will pass 0x10012000(otp+0) instead.

Sections[edit]

Offset Size Description
0x0 0x100 Console-unique data encrypted with AES-CBC. The normalkey and IV are stored in Boot9(retail/devunit have seperate normalkey+IV for this). The last 0x20-bytes of plaintext are a SHA256 hash over the first 0xE0-bytes of plaintext.
0x100 0x8 Before writing REG_SYSPROT9 bit1, the ARM9 copies the 8-byte TWL Console ID here. This sets the registers at 0x4004D00 for ARM7.

Plaintext OTP[edit]

Offset Size Description
0x0 0x4 This is always 0xDEADB00F.
0x4 0x4 This is the u32 DeviceId.
0x8 0x10 This is the fall-back keyY used for movable.sed keyY when movable.sed doesn't exist in NAND(the first two words here are used on retail for generating console-unique TWL keydata/etc). This is also used for "LocalFriendCodeSeed", etc.
0x18 0x1 OTP version
0x19 0x1 This determines if the OTP is for a dev system; it indicates the CTCert issuer type: 0 = retail "Nintendo CA - G3_NintendoCTR2prod", non-zero = dev "Nintendo CA - G3_NintendoCTR2dev".
0x1A 0x6 Manufacturing date (of the SoC?). Usually month(s) before the dates in the logs stored in TWLNAND. Each byte is one field: year, month, day, hour, minute, second. Year is encoded as year-1900 so that it fits in one byte. This order matches up with the layout of a struct tm.
0x20 0x4 This is the CTCert expiry time as UNIX timestamp, this is specified in big endian if the OTP version is <5.
0x24 0x20 This is the CTCert ECDSA privk.
0x44 0x3C This is the CTCert ECDSA signature (sect233r1?/SHA-256).
0x80 0x10 This is all-zero.
0x90 0x50 Used by Boot9 for generating the console-unique AES keyXs. However, due to a bug(?) in Boot9, only the first 0x1C-bytes here actually affect console-unique key generation. The rest of the data is used for hashing, but that output hash only gets overwritten without being used afterwards.

Note that the size passed to the Boot9 keyinit code for console-unique-buffer-size is 0x70, hence this includes the below OTP hash.

0xE0 0x20 SHA256 hash over the previous 0xE0-bytes.