Imports/exports don't always use the title key. Exporting a title and
importing it back uses the PRNG key (aka backup key handle or key #5),
not the title key (at all).
To make things even more fun, some versions of IOS have a bug that
causes it to use a zeroed key instead of the PRNG key. When Nintendo
decided to fix it, they added checks to keep using the zeroed key only
in affected titles to avoid making existing exports useless.
(Thanks to tueidj for drawing my attention to this.
I missed this edge case during the initial implementation.)
This commit implements these checks so we are using the correct key
in all of these cases.
We now also use IOSC for decryption/encryption since built-in key
handles are used. And we now reject any invalid common key index,
just like ES.
This commit merges the import and export contexts into a single context
because this is what IOS does, which means we can only reproduce its
behaviour correctly if we use a single context for both operations.
The other reason is that having two separate and very similar structs
is not really a good idea.
While working on this commit, I was notified that our handling of
ImportTmd/ExportTitleInit is not correct. In particular, we always use
the title key for both importing and exporting, which is wrong. To make
this easier to fix in a follow-up PR, the context now also has a title
key field, just like ES. This also lets us avoid computing it every
single time in ImportContentDone.
Allows them to be reused easily. Still a bit too much duplicated code
in my opinion (OpenContent/SeekContent/ReadContent should just call
FS code), but this is a start.
This is larger than I thought I would be, but unfortunately it's quite
hard to split fixes like this when the handling is wrong in tons of
different places.
The content table is limited in size. It can only hold 16 entries.
Three consequences:
* Since the table cannot grow indefinitely, instead of using a std::map
we use a std::array as we should.
* Remove a hack where the CFD was cleared back to 0 on IPC close (wtf?)
* The CFD now doesn't keep increasing to infinity. It's unknown if this
would fix anything at all, but some issues in the past were caused
by CFDs being excessively large.
Other minor changes:
* Simplify save state logic.
* Keep track of the UID like ES does. Not sure how useful this is, but
we can do this very easily so why not.
* Remove the guesswork and use the actual error codes.
* Add more error checking to make Dolphin less likely to crash.
Something that should be done in the future: deduplicate the filesystem
logic. Something that takes one line in the actual ES code takes
10+ lines in our implementation... while duplicating the FS logic...
This will likely harder to fix though, so I'm leaving that
for another time.
The sanity check runs *before* finalising the import, so at that time
the whole title directory is still in /import and not in /title.
This means we should check for contents there, not in /title. Whoops.
This adds a check to ImportTitleDone to make sure all required contents
that are listed in the TMD have been imported before allowing to finish
the import. Not checking for this could allow titles to be left in an
inconsistent state.
On a real Wii, the title list is not in any particular order. However,
because of how the flash filesystem works, titles such as 1-2 are
*never* in the first position. We must keep this behaviour, or some
versions of the System Menu may break.
Will be used from several functions to verify the signatures for
different containers (TMDs, tickets, device signed blobs).
An option was added to disable signature checks, because that could be
useful for people trying to import unsigned stuff.
This ioctlv is used to get an IOSC decrypt handle for a title.
It is known to be used internally by the WFS modules, but it can also
be used from the PPC under some conditions.
Brings us down to 2 essentially unimplementable ioctlvs (syscalls which
seem to return kernel thread priorities...), and 1 known but
unimplemented ioctlv (VerifySign).
In the future, NAND filesystem access will be limited to one IOS
instance, for safety reasons and to make it possible to consider
supporting NAND images. This means that any code accessing the NAND
filesystem must go through the FS device, both for code that is
external to IOS and internal.
Because we don't want to introduce any singleton, this requires
internal IOS code that needs NAND access to be part of an IOS device
class, so they can access the FS device easily.
Making some of the internal ES implementation functions member
functions also prevents them from being (mis)used outside of IOS,
since they cannot be called everywhere anymore.
* Move out boot parameters to a separate struct, which is not part
of SConfig/ConfigManager because there is no reason for it to
be there.
* Move out file name parsing and constructing the appropriate params
from paths to a separate function that does that, and only that.
* For every different boot type we support, add a proper struct with
only the required parameters, with descriptive names and use
std::variant to only store what we need.
* Clean up the bHLE_BS2 stuff which made no sense sometimes. Now
instead of using bHLE_BS2 for two different things, both for storing
the user config setting and as a runtime boot parameter,
we simply replace the Disc boot params with BootParameters::IPL.
* Const correctness so it's clear what can or cannot update the config.
* Drop unused parameters and unneeded checks.
* Make a few checks a lot more concise. (Looking at you, extension
checks for disc images.)
* Remove a mildly terrible workaround where we needed to pass an empty
string in order to boot the GC IPL without any game inserted.
(Not required anymore thanks to std::variant and std::optional.)
The motivation for this are multiple: cleaning up and being able to add
support for booting an installed NAND title. Without this change, it'd
be pretty much impossible to implement that.
Also, using std::visit with std::variant makes the compiler do
additional type checks: now we're guaranteed that the boot code will
handle all boot types and no invalid boot type will be possible.
This commit moves the write function to where it should be (IOS),
especially when ES::ImportTicket() is the only place to use it.
Prevents misusing the ticket import function, and removes one unsafe
direct write to the NAND that does not go through IOS.
This also fixes the destination path: the session root is the one which
should be used for determining the ticket path, not the configured one.