ACT Services
The ACT module handles NNID accounts. This module behaves very similarly to the Wii U implementation (nn::act)
ACT User Service "act:u"
These commands are used generally by most titles, and are also present in act:a.
ACT Admin Service "act:a"
This service is used mainly by the Nintendo Network ID Settings application accessible in System Settings.
Account slots
Like the friends sysmodule, the ACT module has support for multiple console accounts. The ACT sysmodule has support for 8 account "slots", which are 1-indexed numbers (n) referring the to the n
th account. This means that up to 8 different console accounts can be used with the ACT sysmodule, unlike the Wii U, which has support for 12. This multi-account functionality is not exposed to users, and the Nintendo Network ID Settings application only ever uses the default account slot.
When the ACT sysmodule is started, it loads the default account slot. The default account can be set using ACTA:SetDefaultAccount.
It is also possible to change the account slot number of an account by using ACTA:SwapAccounts.
Account slot -2 (0xFE) always refers to the currently loaded account.
Console Accounts
A "console account" refers to a specific account slot, and may or may not be associated with a Nintendo Network ID (server account). By default, there is only one console account.
More console accounts can be created using ACTA:CreateConsoleAccount, loaded using ACTA:LoadConsoleAccount, unloaded using ACTA:UnloadConsoleAccount, or deleted using ACTA:DeleteConsoleAccount.
Server Accounts
A "server account" is essentially a Nintendo Network ID.
Associating a console account with a Nintendo Network ID (server-side) is facilitated by the commands ACTA:BindToNewServerAccount (to create and link an NNID) or ACTA:BindToExistentServerAccount (to log into an existing linked NNID).
Nintendo Network IDs can be transferred to other consoles using ACTA:ReserveTransfer initially, and then ACTA:CompleteTransfer.
NNIDs can be deleted using either ACTA:DeleteServerAccount, ACTA:InactivateAccountDeviceAssociation, ACTA:DeleteAccountDeviceAssociation or ACTA:ReserveServerAccountDeletion.
Password Management
The ACT sysmodule uses a distinct password management system.
Password Hashing Algorithm
Passwords are not stored in plaintext. Instead, they are hashed using the following algorithm:
void hash_password(void *out_hash, void *input, int input_size, unsigned int num_iterations, unsigned int principal_id) { static const unsigned char constant[4] = { 0x02, 0x65, 0x43, 0x46 }; unsigned char hash_data[8 + 32] = { 0 }; unsigned int bswap_pid = bswap32(principal_id); while ( num_iterations-- ) { memcpy(&hash_data[0], &bswap_pid, 4); memcpy(&hash_data[4], &constant, 4); memcpy(&hash_data[8], input, input_size); /* output, input, size */ sha256(out_hash, hash_data, 8 + input_size); input_size = 32; input = out_hash; } }
Account Password Hash
The AccountPasswordHash field in the account data is the result of one iteration of the above algorithm, using the plaintext password as the input. It is generally used to verify the input password in ACTA:LoadConsoleAccount.
This field in the account data is set when ACTA:BindToNewServerAccount, ACTA:BindToExistentServerAccount, or ACTA:UpdateAccountPassword is used.
Account Password Cache
It is possible to cache the password for an account so the user isn't asked for it every time. This can be configured in Nintendo Network ID settings or during an NNID login prompt (e.g. in the eShop). The AccountPasswordCache field in the account data is the result of two iterations of the above algorithm, using the plaintext password as the input.
Account Password Input
The account password input represents the in-memory input value of the password. It can be thought of as the value that will be autofilled by default in a login form. When the ACT sysmodule is started and the default account is loaded, the AccountPasswordCache is copied to the AccountPasswordInput, allowing automatic login.
However, it is possible to override this value using ACTA:SetAccountPasswordInput. The AccountPasswordInput value set using this command can then be saved to the account password cache by using ACTA:EnableAccountPasswordCache.
The account password cache can be enabled or disabled through ACTA:EnableAccountPasswordCache.
The AccountPasswordInput is always loaded into memory and is not saved to the system save data.
Server Types
The ACT sysmodule uses two different server types for Nintendo Network accounts.
See below how these types are determined by default. These types can also be overridden using ACTA:SetHostServerSettings, ACTA:SetDefaultHostServerSettings, ACTA:SetHostServerSettingsStr, and ACTA:SetDefaultHostServerSettingsStr.
The base URL for the Nintendo Network Account Server (NNAS) is: https://[<prefix>]account.nintendo.net
.
NNAS (Nintendo Network Authentication Server) Types
This is used to determine the NNAS subdomain used for the account server.
Value | Description | NNAS Subdomain | Complete NNAS URL |
---|---|---|---|
0 | Production | (None) | https://account.nintendo.net
|
1 | Game Development (also the default for debug mode on developer units) | game-dev. |
https://game-dev.account.nintendo.net
|
2 | System Development | system-dev. |
https://system-dev.account.nintendo.net
|
3 | Library Development | library-dev. |
https://library-dev.account.nintendo.net
|
4 | Staging | staging. |
https://staging.account.nintendo.net
|
Values beyond 4 are considered invalid.
Default NNAS Server Types
By default, ACT uses the letter value from FRDU:GetServerTypes to determine the correct NNAS subdomain when a Nintendo Network ID is created.
Value from FRDU:GetServerTypes | NNAS Server Type | Corresponding NNAS Subdomain | Corresponding complete NNAS URL |
---|---|---|---|
0 (L) | Production (default on retail units) | (None) | https://account.nintendo.net
|
2 (S) | Staging | staging. |
https://staging.account.nintendo.net
|
3 (D) | Game Development (also the default for debug mode on developer units) | game-dev. |
https://game-dev.account.nintendo.net
|
5 (T) | Library Development | library-dev. |
https://library-dev.account.nintendo.net
|
7 (J) | System Development | system-dev. |
https://system-dev.account.nintendo.net
|
NFS (Nintendo Friend Server) Types
ACT uses the same Server Types as the friends sysmodule as the NfsType.
A small subset of these types are used in ACTA:SetHostServerSettings, ACTA:SetDefaultHostServerSettings, ACTA:SetHostServerSettingsStr, and ACTA:SetDefaultHostServerSettingsStr:
Input value used in ACT commands | Corresponding Friends Server Type value |
---|---|
0 | 0 (L) |
1 | 3 (D) |
2 | 2 (S) |
3 | 5 (T) |
4 | 7 (J) |
Default NFS Server Types
By default, ACT uses FRDU:GetServerTypes to obtain the correct NFS (Nintendo Friend Server) environment to create Nintendo Network IDs.
This is necessary to ensure proper online play functionality, because the friends server account is tied to the Nintendo Network ID when one is linked.
UUIDs
The ACT service generates UUIDs for accounts and for the console in general.
All UUIDs generated by the service are RFC9562 Version 1 UUIDs.
Node Data
In general, the following 48-bit node data is used.
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | Always set to 1 |
0x1 | 0x1 | Always set to 0 (related to parental controls?) |
0x2 | 0x4 | Byte-Swapped value from AM:GetDeviceId |
UUID Types
Regular UUIDs
These are just standard RFC9562 Version 1 UUIDs with the above node data.
Title-specific UUIDs
These UUIDs are specific to the title that requested them to be generated, specifically, using the unique ID portion of the title ID of that title.
The following technique is used internally to generate these UUIDs:
- Generate or use an existing regular UUID the with the above mentioned node data (regular_uuid
)
- hash = SHA256 ( byte-swapped unique ID (thus, big endian) + 095E273A + 48-bit node data from regular_uuid )
- output_uuid = regular_uuid[0:9] + hash[10] | 0x1 + hash[11:16]
Independent Service Tokens
In addition to NEX tokens for gameserver authentication in combination with Nintendo Network, app developers have the ability to use their own independent services. For authenticating with such services through Nintendo Network, the service's client ID is used to request a token from the account server.
Independent Service Token Versions
There are two versions of independent service tokens.
V1 Independent Service Token
These are more basic, consisting of only a base64 token. These can be requested and cached using ACTU:AcquireIndependentServiceToken, retrieved either immediately after requesting them using ACTU:GetIndependentServiceToken or from an internal cache using ACTU:GetCachedIndependentServiceToken.
Offset | Size | Description |
---|---|---|
0x0 | 0x200 + 1 | base64 NULL-terminated Token |
V2 Independent Service Token
V2 indpendent service tokens include more fields like an IV, signature, and account server environment compared to V1 tokens.
They can be requested and cached using ACTU:AcquireIndependentServiceTokenV2, retrieved either immediately after requesting them using ACTU:GetIndependentServiceTokenV2 or from an internal cache using ACTU:GetCachedIndependentServiceTokenV2.
Offset | Size | Description |
---|---|---|
0x0 | 0x200 + 1 | base64 NULL-terminated Token |
0x201 | 0x18 + 1 | base64 NULL-terminated IV |
0x21A | 0x158 + 1 | base64 NULL-terminated Signature |
0x373 | 0x2 + 1 | ASCII Server Environment type and number |
DataBlocks
Data blocks can be accessed from specific commands depending on the data that is requested. These follow a similar order to the Wii U ACTInfoTypes.
BlkID | Size | Command needed | Description | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x1 | 0x1 | GetCommonInfo | Number of accounts | ||||||||||||||||||||||||||||||
0x2 | 0x1 | GetCommonInfo | Current account slot | ||||||||||||||||||||||||||||||
0x3 | 0x1 | GetCommonInfo | Default account slot | ||||||||||||||||||||||||||||||
0x4 | 0x8 | GetCommonInfo | NetworkTimeDifference: Difference between server time and UTC device time (in nanoseconds) | ||||||||||||||||||||||||||||||
0x5 | 0x4 | GetAccountInfo | PersistentId | ||||||||||||||||||||||||||||||
0x6 | 0x8 | GetCommonInfo/GetAccountInfo | CommonTransferableIdBase on GetCommonInfo / TransferableIdBase on GetAccountInfo | ||||||||||||||||||||||||||||||
0x7 | 0x60 | GetAccountInfo | Mii CFLStoreData | ||||||||||||||||||||||||||||||
0x8 | 0x11 | GetAccountInfo | AccountId (ASCII NULL-terminated Nintendo Network ID) | ||||||||||||||||||||||||||||||
0x9 | 0x101 | AcquireAccountInfo | Mail address | ||||||||||||||||||||||||||||||
0xA | 0x4 | GetAccountInfo | Birth Date | ||||||||||||||||||||||||||||||
0xB | 0x3 | GetAccountInfo | ASCII NULL-terminated Country Name | ||||||||||||||||||||||||||||||
0xC | 0x4 | GetAccountInfo | PrincipalId | ||||||||||||||||||||||||||||||
0xE | 0x1 | GetAccountInfo | IsPasswordCacheEnabled | ||||||||||||||||||||||||||||||
0xF | 0x1 | GetAccountInfo | Does not return anything. | ||||||||||||||||||||||||||||||
0x11 | 0xA0 | GetAccountInfo |
| ||||||||||||||||||||||||||||||
0x12 | 0x4 | GetAccountInfo | Account server types
| ||||||||||||||||||||||||||||||
0x13 | 0x1 | GetAccountInfo | Gender | ||||||||||||||||||||||||||||||
0x14 | 0x1 | GetAccountInfo | LastAuthenticationResult | ||||||||||||||||||||||||||||||
0x15 | 0x11 | GetAccountInfo | AssignedAccountId (ASCII NULL-terminated Nintendo Network ID) | ||||||||||||||||||||||||||||||
0x16 | 0x1 | GetAccountInfo | ParentalControlSlotNo | ||||||||||||||||||||||||||||||
0x17 | 0x4 | GetAccountInfo | SimpleAddressId (CountryInfo) | ||||||||||||||||||||||||||||||
0x19 | 0x8 | GetAccountInfo | UtcOffset | ||||||||||||||||||||||||||||||
0x1A | 0x1 | GetAccountInfo | IsCommitted | ||||||||||||||||||||||||||||||
0x1B | 0x16 | GetAccountInfo | 10-character UTF-16 Mii Name (10 characters + NULL termination) | ||||||||||||||||||||||||||||||
0x1C | 0x11 | GetAccountInfo | ASCII NULL-terminated NfsPassword | ||||||||||||||||||||||||||||||
0x1D | 0x1 | GetAccountInfo | HasEciVirtualAccount (checks whether EciVirtualAccount has a value) | ||||||||||||||||||||||||||||||
0x1E | 0x41 | GetAccountInfo | TimeZoneId (ASCII Time Zone Location) | ||||||||||||||||||||||||||||||
0x1F | 0x1 | GetAccountInfo | IsMiiUpdated | ||||||||||||||||||||||||||||||
0x20 | 0x1 | GetAccountInfo | IsMailAddressValidated | ||||||||||||||||||||||||||||||
0x21 | 0x4C | GetAccountInfo | (Developer units only) Account access token
| ||||||||||||||||||||||||||||||
0x22 | 0x1 | GetCommonInfo | IsApplicationUpdateRequired | ||||||||||||||||||||||||||||||
0x23 | 0x4 | GetCommonInfo | Default account server types
| ||||||||||||||||||||||||||||||
0x24 | 0x1 | GetAccountInfo | IsServerAccountDeleted | ||||||||||||||||||||||||||||||
0x25 | 0x101 | GetAccountInfo | MiiImageUrl (ASCII NULL-terminated URL to account mii image) | ||||||||||||||||||||||||||||||
0x26 | 0x4 | GetAccountInfo | AssignedPrincipalId | ||||||||||||||||||||||||||||||
0x27 | 0x4 | GetAccountInfo | Account Access token state, only accessible with account slot = 0xFE: (0: uninitialized, 1: expired, 2: valid) | ||||||||||||||||||||||||||||||
0x28 | 0x24 | GetAccountInfo | Account server environment
| ||||||||||||||||||||||||||||||
0x29 | 0x24 | GetCommonInfo | Server environment of default account
| ||||||||||||||||||||||||||||||
0x2A | 0x8 | GetCommonInfo | DeviceHash: first 8 bytes of SHA256 ( AM:GetDeviceId() as 4 little endian bytes + A2257354 )
| ||||||||||||||||||||||||||||||
0x2B | 0x1 | GetAccountInfo | FpLocalAccountId (local account ID of friends sysmodule) | ||||||||||||||||||||||||||||||
0x2C | 0x2 | GetAccountInfo | Age (calculated using server time, not device time) | ||||||||||||||||||||||||||||||
0x2D | 0x1 | GetAccountInfo | IsEnabledReceiveAds | ||||||||||||||||||||||||||||||
0x2E | 0x1 | GetAccountInfo | IsOffDeviceAccessEnabled | ||||||||||||||||||||||||||||||
0x2F | 0x4 | GetAccountInfo | Translated SimpleAddressId (CountryInfo) |
Types
Birthdate
Offset | Size | Description |
---|---|---|
0x0 | 0x2 | u16, Year |
0x2 | 0x1 | u8, Month |
0x3 | 0x1 | u8, Day |
CFLStoreData
This is the Mii format used in ACT commands.
Offset | Size | Description |
---|---|---|
0x0 | 0x5C | Mii Data |
0x5C | 0x2 | padding |
0x5E | 0x2 | CRC16 over the above 0x5E bytes (see Mii Checksum for details on the algorithm) |
Timezone
Offset | Size | Description |
---|---|---|
0x0 | 0x40 + 1 | ASCII NULL-terminated TimezoneArea (max. 64 characters + NULL termination) |
0x41 | 0x3 | padding |
0x44 | 0x40 + 1 | ASCII NULL-terminated TimezoneId (max. 64 characters + NULL termination) |
0x85 | 0x3 | padding |
0x88 | 0x8 | s64, UtcOffset in seconds |
AcquireTimeZoneListData
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | u32, Capacity (32) |
0x4 | 0x4 | u32, Count |
0x8 | 0x90 * Capacity | Timezones |
EulaInfo
Offset | Size | Description |
---|---|---|
0x0 | 0x2 + 1 | ASCII NULL-terminated two-letter country code (2 characters + NULL termination) |
0x3 | 0x2 + 1 | ASCII NULL-terminated two-letter language code (2 characters + NULL termination) |
0x6 | 0x2 | u16, EULA version |
InquireBindingToExistentServerAccountData
Represents the device information for the console linked to the NNID.
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | bool, HasMii |
0x1 | 0x3 | padding |
0x4 | 0x60 | Mii CFLStoreData |
0x64 | 0x4 | u32, PrincipalId |
0x68 | 0x1 | bool, CoppaRequiredFlag |
0x69 | 0x3 | padding |
0x6C | 0x5 + 1 | ASCII 5-character CoppaCode + NULL termination |
0x72 | 0x100 + 1 | ASCII 256-character ParentEmail + NULL termination |
0x173 | 0x1 | padding |
0x174 | 0x4 | Birth Date |
SendCoppaCodeMailData
Offset | Size | Description |
---|---|---|
0x0 | 0x5 + 1 | 5-character ASCII CoppaCode + NULL termination |
0x6 | 0x100 + 1 | 256-character ASCII ParentEmail + NULL termination |
AcquireEulaData/AcquireEulaListData
Data returned from ACTU:AcquireEula and ACTU:AcquireEulaList uses a special format.
EulaHeader
Offset | Size | Description |
---|---|---|
0x0 | 0x3 | 2-character Country code + NULL termination |
0x3 | 0x1 | padding |
0x4 | 0x3 | 2-character Language code + NULL termination |
0x7 | 0x1 | padding |
0x8 | 0x2 | u16, Version |
0xA | 0x2 | padding |
0xC | 0x4 | u32, end offset of this EULA within full data blob |
0x10 | 0x4 | EulaType offset |
0x14 | 0x4 | AgreeText offset |
0x18 | 0x4 | NonAgreeText offset |
0x1C | 0x4 | LanguageName offset |
0x20 | 0x4 | MainTitle offset |
0x24 | 0x4 | MainText offset |
0x28 | 0x4 | SubTitle offset |
0x2C | 0x4 | SubText offset |
X offset
refers to an offset to a NULL-terminated ASCII string value for X
within the full EULA data blob (see below).
EulaList
This is the full data blob retrieved using ACTU:GetAsyncResult. Each EULA list entry is appended at the very end of the previous one. The end offset in the header can be used to get to subsequent EULA list entries.
Offset | Size | Description | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
0x0 | 0x1 | u8, Number of EULA list entries (n) | |||||||||
0x1 | n * (...) | concatenated EULA list entries
|
HTTPS Requests
With each request, ACT-sysmodule specifies request-header "X-Nintendo-Device-Model". This is the only *dedicated* request-header that's contains anything Old3DS/New3DS specific. This was implemented with 9.0.0-X, and presumably 8.1.0-0_New3DS. The value is from a string initialized during ACT-sysmodule startup. The value-string is the codename string for all 5 of the model values from Cfg:GetSystemModel. When the output from GetSystemModel is >=5(switch statement default case), it runs this: "len = snprintf(outstr, outmaxsize, "3DS-%u", model);"
Trusted Root CAs
ACT module uses a RootCertChain for all HTTPS requests, the only trusted root CA is default CertID 0x3.
New3DS
Even though ACT-sysmodule uses ptm:s, it doesn't use CheckNew3DS at all.