How the firmware updates work on Toyota Touch & Go

How the firmware updates work on Toyota Touch & Go

Before I start, here’s the TL;DR: Custom firmwares are not possible for Touch & Go without breaking open the device and possibly soldering stuff on it. Don’t try it – you’ll most probably ruin your device.

Now that we have that out of the way, let’s continue.

Out of curiosity, I wanted to find out what’s lurking inside the Touch & Go unit I have on my car. The device itself reveals very little information about its internals, but a firmware update image provided by the manufacturer was a great source for lots of interesting information.

As has already been determined, the head unit runs the QNX Neutrino operating system. The board appears to be based on a TI DM3730 (OMAP3 ARMv7) SoC and all the radio, navigation, etc. functionality is provided by a Toyota-specific extension box which may be running a Renesas V850 and a firmware of it’s own.

The board has a NAND flash chip which is divided between IPL, IFS and ETFS partitions. The first two are read-only and loaded into RAM on bootup. The ETFS is a read/write filesystem, so the updater scripts can delete, replace and add individual files on it.

Additionally, an MMC card (probably not a physical card, though) is mounted on /fs/mmc0/ifs for system data.

Updating the device completely replaces the IPL and IFS images in the onboard NAND, so looking at /usr/share/IFS/ifs-extbox.bin in the ISO image probably lets us see something close to what’s currently on the device’s IFS.

Dumping the IFS image reveals a bunch of interesting stuff, such as the boot scripts, validation keys and various ARM binaries. So let’s take a short look at what happens when the device boots up for updating.

On powerup, the execution starts from the IPL, which is something akin to the BIOS and MBR on PCs. The IPL locates the system image, loads the process manager (procnto-instr) and transfers control to it, which then continues the boot process by starting the boot script off the IFS.

The boot script first starts several system services and then calls another script called /bin/ This script first reads the FRAM at offset 3 and checks whether the byte contained there is ‘U’. If true, the system is determined to be in update mode.

inject -e -i /dev/mmap/swdl -d /tmp/bootmode -o 3 -s 1

The update package is expected to be delivered on an USB mass storage device, so the boot script waits up to 10 seconds for /fs/usb0/swdl.iso to appear. Once found, it will proceed to authenticate the ISO image.

It first calculates an SHA256 digest from the ISO image and stores it into /tmp/swdl.iso.digest. The utility isodigest apparently either ignores the first 64 bytes or just regards them as zeroes. We’ll assume the latter.

isodigest -df /tmp/swdl.iso.digest /fs/usb0/swdl.iso

Once a digest has been made, the signature is extracted from the beginning of the ISO image. The first 64 bytes contain the signature and it’s stored into /tmp/isodigest.sha256.

inject -e -i /fs/usb0/swdl.iso -f /tmp/isodigest.sha256 -o 0 -s 64

For example, signature on swdl.iso for 2011-12-08 update:

00000000   77 82 f9 9a 16 d6 57 c0 0a 88 3a 16 78 e1 d7 c2
00000010   65 48 7f 61 2a 7c e8 b6 e7 f8 b1 45 64 04 8d b9
00000020   9f 21 95 39 69 6c dc d3 70 97 d9 3b b1 89 e2 22
00000030   35 a5 69 9d f3 91 e9 e5 32 78 7e 29 2f 36 a0 51

The startup script will then scan all .pub files stored in /etc/keys/ on the IFS. Currently there are five public keys in PEM format:

274000   b6   etc/keys/
275000   b6   etc/keys/
276000   b6   etc/keys/
277000   b6   etc/keys/
278000   b6   etc/keys/

The script verifies the signature against each public key. If the calculated digest matches the signature (ie. the ISO has not been tampered with and the signature has been signed with one of Toyota’s private keys), the script returns “Verified OK” and environment variable AUTHENTICATED is set to 1. If after processing all keys the variable is blank, the script will quit with an error.

Authenticating is done by calling OpenSSL with the following command line for each key in /etc/keys/:

openssl dgst -sha256 -verify /etc/keys/ -signature \
/tmp/isodigest.sha256 /tmp/swdl.iso.digest

If authentication went OK, the ISO image is mounted and the IFS image on the ISO is loaded to RAM. This secondary IFS contains all the system executables required for the actual update process.

memifs2 -q -d /fs/usb0/usr/share/swdl.bin /

Unfortunately swdl.bin is not a standard IFS image, but instead appears to be some (loosely) compressed format with a ‘hbcifs‘ header. Apparently it is decompressed and loaded into RAM by memifs2, but there’s no documentation available for this utility. Finding out more about the ‘hbcifs‘ format would potentially require disassembling /usr/bin/memifs2 provided on the primary IFS.

Finally, with the secondary IFS loaded, turns over control to another script, /usr/share/scripts/ on the ISO image. This script then continues the update process by flashing the new IPL and IFS images and modifying the ETFS and MMC filesystems. The lua scripts used for this are plainly visible on the ISO image.

Of course, without knowing one of the private keys Toyota uses to sign the images, it’s impossible to make custom firmware images. The only way around this would be to somehow inject our own public key to /etc/keys/ by modifying the IFS partition on the NAND. The most common way to modify NAND contents in other devices is by opening the device and reflash using possible JTAG pins inside the unit.

Although JTAG headers are ubiquitous on embedded systems, it is very possible that a production device only has solder points without actual pins. In this case we’d have to modify the board by adding the pins in order to be able to use a programmer device.

An alternative to flashing via JTAG is getting shell access on the device via TCP/IP and reflashing the IFS using the built-in tools on the device. The guys at Tarlab Oulu have discovered that the device has an open telnet service on port 23 and presents a login prompt. If a username/password combination for logging into shell with root access is found, the device is open for flashing any images from mounted USB storage devices.

Given the hypothetical situation that we have found the capability to inject our own public key into the system, we could do this by first generating a key pair using OpenSSL:

openssl genrsa -out private.pem 512
openssl rsa -in private.pem -out public.pem -outform PEM -pubout

Now, assuming that the ‘isodigest’ utility regards the first 64 bytes as zeroes, we need to first zero out them on our custom update image:

dd bs=64 count=1 if=/dev/zero of=custom_swdl.iso conv=notrunc

Now generate the signed digest from our custom swdl.iso:

openssl dgst -sha256 -sign private.pem -binary < \
custom_swdl.iso > signature

Finally, overwrite the first 64 bytes of the ISO image with the signature:

dd bs=64 count=1 if=signature of=custom_swdl.iso conv=notrunc

Now, assuming that we have somehow managed to inject our public.pem to the device as, for example /etc/keys/, our custom swdl.iso should pass the validation in the update script.

However, given the number of uncertainties and assumptions, the above procedure is pretty much academical and, with a high probability, would not work. Further research would require hands-on experimentation on an actual ARMv7 platform, such as the BeagleBoard-XM, which is also based on the DM3730.

While this little research project didn’t result in a procedure for custom firmwares, it was certainly interesting to see how a modern embedded device, similar to mobile phones and game consoles, performs firmware updates securely even when the user has physical access to the device. I tip my hat to all hackers who have successfully discovered ways to jailbreak their various devices.

17 thoughts on “How the firmware updates work on Toyota Touch & Go

  1. Hi,
    after reading your interesting article, I have two questions:

    1) I have not understood how the FRAM byte check at the beginning works: the update is delivered on a USB stick which is mounted after the third byte is checked in the FRAM. How does the system knows it is in update mode if the USB is still not mounted ? Is it always in update mode ?

    2) the T&G toolbox is very likely able to sign the iso with a key known to the system. First time you plug the usb key with the toolbox running, it downloads an iso used to install apps on the system; the iso is just an empty updater, with nothing to install. After you select the app on the myToyota website, the toolbox download the app and adds it to the update ISO. The system recognise the update iso and hence it must be signed by the toolbox. I look into all toolbox dll’s to find an exported function which might be used to sign the iso, my by software abilities are limited… have you tried looking at the toolbox software package ?


    1. Hi!

      1) I’m not sure about this. My assumption was that when you have the system running normally and insert a USB mass storage device with swdl.iso in the root directory, the system asks if you want to update. If the update is confirmed, it instructs the user to keep the USB device connected, writes the ‘U’ to FRAM and reboots. The boot script then detects the update mode and continues with the actual update. The progress bars are displayed by the updater script on the ISO image.

      2) Ah – interesting. If the ISO image is indeed modified by the toolbox, it surely must contain at least some of the private keys corresponding to the public keys on the IFS image. Unfortunately I’m not very well versed in Windows software development, so I haven’t looked into the toolbox software.

  2. A custom firmware may be well beyond what’s really needed.
    Some touch and go units allow downloading of apps from Toyota.
    Have you found any evidence that these apps are also signed with Toyota keys, or there’s some chance to develop and run custom apps?

  3. Thank you for very detailed description of authentification process of T&G. We were wondering why it doesn’t works. Did you checked our website obout T&G.
    I posted the map updates, which they do in service here:

    Furhtemore there are newest images available, but we can not use them, because it asks about authentification code, which requires some Generator. Check this here:
    It would be great, if you could help us managing the system to work.

  4. It could well be that the toolbox calculates the digest and sends it over to Toyota servers (including device ID) to have it signed, that way the keys don’t need to be in the toolbox.

  5. Very interesting research here jh ! You are going the hardware method and it is very interesting !

    As Enrico, I looked on the software side (the Toolbox), because afterall it is this software that orders everything.
    Well, I sniffed the packet sent between the toolbox and the outside world.
    It appears that all the connections made are done at the application startup. It asks the remote site some new things to update for our systems.
    So it appears that our system entirely is remotely saved on the Toyota servers. They know if an update has been bought for our system and then send us the update through the application.

    I have dowloaded a full map/software update here :

    Once uncompressed, the file structure is the same as the one saved by the Touch&Go System on our USB key. Thing is, how the toolbox arrange everything ?
    Inside those folders we can see some md5 checksum files.
    Besides, the parent folder is named NNG… (samed editor as the iGo…)

    If we can get the structure that the Touch&Go Software makes on the USB key once the update is ordered through the Software and the process of signing the ISO, then we can win this match I think :) Besides, I think we might also compromise the connection to the remote Toyota servers…

    Still working on this topic…

  6. I there a potential opening for injecting an unsigned update into the update process. Having a legitimate SWDL.iso file that would pass the digest check, and then swapping the SWDL.iso with an unsigned one before it is mounted for flashing. It looks like the key check and digest are handled by different processes than the mounting. This would require a special memory stick (such as a wireless one, connected to a PC). Also timing would be important, as you would switch the ISO files after the digest. You could then put your own public key in your unsigned update and then be able to sign future updates.

    1. The private key used for signing the updates is not stored on the device itself, so it cannot be obtained by exploiting any vulnerabilities on the embedded software. As Enrico wrote earlier, it may be possible to extract it from the toolbox application on Windows but I have no further information on that.

      1. Fortunately I have connected with my Toyota T&G via JTAG, I have read data at address 0x84000000 and it is ifs image which next is mounted during startup, in this IFS image there are private keys. Navi unit have also uart (some pins in red connector on the board) so I was able to see what is going on during startup. Unfortunately via this uart connection I was no able to do anything because I don’t know user name and password ;(

        Below output from uart:

        QNX Neutrino Initial Program Loader for Texas Instruments OMAP3730 TEB Gamma Boards
        IPL Version 1.8.14

        Booting from IPL: 00000000
        Check FRAM FLAG for Primary Partition slot 00000000……..
        reading from NAND flash at partition 00000000……..
        4-bit ecc on page 00000214
        Page: 00000214 Sector: 00000000 err found: 00000001 err fixed: 00000001
        read from NAND flash OK
        Calculating new checksum…success
        Uploading local buffer to FRAM…
        No need to update fram bank
        No need to update fram bank
        Found image @ 0x84000008
        Jumping to startup @ 0x801004C0

        CPU0: L1 Icache: 512×64
        CPU0: L1 Dcache: 512×64 WB
        CPU0: L2 Dcache: 4096×64 WB
        CPU0: VFP-d32 FPSID=410330c3
        CPU0: NEON MVFR0=11110222 MVFR1=00011111
        CPU0: 413fc082: Cortex A8 rev 2 800MHz
        Loading IFS…decompressing…done

        System page at phys:80010000 user:fc404000 kern:fc404000
        Starting next program at vfe04ba30
        cpu_startnext: cpu0 -> fe04ba30
        VFPv3: fpsid=410330c3
        coproc_attach(10): replacing fe07b458 with fe07acf8
        coproc_attach(11): replacing fe07b458 with fe07acf8

        == Toyota Extension Box Boot IFS ==
        == Variant:EU-Low HWRev:Gamma Arch:armle-v7 ==
        == built by Jenkins_FH on Fri May 15 15:19:13 2015 ==

        memifs2 with 4-bit ECC

        Memifs2 with error correction and not using FRAM
        Using dma option
        TEMP: MOUNT total 128.0 ms (comp: 14594.0 kB/s, uncomp: 31046.8 kB/s)
        Primary Part 2 IFS loaded successfully
        memifs2 with 4-bit ECC

        Memifs2 with error correction and not using FRAM
        requested sub partition = 3
        Using dma option
        TEMP: MOUNT total 1122.5 ms (comp: 16350.8 kB/s, uncomp: 29744.8 kB/s)
        Secondary IFS loaded successfully
        New ETFS driver using nand_partition file
        ETFS reserve_value = 147968 based on partition file /etc/system/config/nand_partition.txt
        g_nand_upper_bound_min = 1156
        Spec compliant display settings – 60Hz
        multicored [000000002.390]:version 4.4.g, verbosity 1 (supported 4), scope 0x00000001, console: /dev/ser1 (fd=3), FILE_LOGGING, TESTCONTROL, DYNAMIC_LOAD
        multicored [000000002.393]:dbg_restart 2
        multicored [000000002.398]:using 250 buffers of size 1460 (total 365000 bytes)
        multicored [000000002.415]:going quiet
        Service com.harman.service.TimeMgr just appeared at time 2.613358 seconds
        Service com.harman.service.PersistentKeyValue just appeared at time 3.008661 seconds
        Service com.harman.service.AudioCtrlSvc just appeared at time 3.046616 seconds
        Service com.harman.service.csi_SqlDatabase just appeared at time 3.068951 seconds
        Service com.harman.service.poi_SqlDatabase just appeared at time 3.117452 seconds
        Service com.harman.service.ConnMgr just appeared at time 3.326108 seconds
        Service com.harman.service.DeviceInput just appeared at time 5.310612 seconds
        Service com.harman.service.Media just appeared at time 5.788080 seconds
        Service com.harman.service.ToyotaMGR just appeared at time 5.995599 seconds
        Service com.harman.service.HMIService just appeared at time 12.322998 seconds
        Service com.harman.service.NDR just appeared at time 14.275592 seconds
        Service com.harman.service.Tuner just appeared at time 14.454916 seconds
        Service com.harman.service.authenticationService just appeared at time 14.724282 seconds

        1. Can you post picture of connector and which pins are used for connection by terminal, rx, tx, gnd on motherboard?

          I want check it little bit… And if you have some dump of it, would be nice to share it, in case we need it at our researching.

  7. @tomuro,

    Thanks a lot for confirming the UART. This is very interesting as this processor allow many boot operations (including serial boot).

    Question – could you please also confirm the pinout for the JTAG interface? Thanks,

  8. Hello friends,
    I have ability to desolder and to read entire EMMC nand chip. If someone can help to inject public keys it will be great.

  9. I have a Navi unit in my Prius and it looks like both TnGo and Navi use the exact same software architecture. From what I have seen, the Navi units have an OMAP 3530 vs 3730, but the differences are minimal.

    With respect to getting the username / password for the local terminal, would it be possible to desolder the flash and read /etc/password or /etc/shadow directly? I realize the value would be hashed and not the password, but with Rainbow tables on the internet, it shouldn’t be all that hard to reverse the cleartext.

  10. Hey,
    is there any chance somebody could take pictures of the chips on the board inside the navigation unit? I am very interested in the connection between the navigation box and the head unit, to find out if it would be possible to connect something other than the original box…

Leave a Reply

Your email address will not be published. Required fields are marked *