Read the official documentation as well
Proceed at your own risk (which is quite low)
Intro
This guide aims to concentrate all the information necessary to get your toniebox up and running with teddycloud. The individual places, where you can find the information are well written and explain everything. When I started out it was difficult for me to put everything together in the right order. Thus the motivation for this guide: providing a one stop place, where you can find all the information you need with links to where you can get in depth information.
I will assume some basic knowledge regarding the command line and docker. Some steps where there may be pitfalls are explained in more detail, however I cannot walk you through every single step in detail. This will not be a guide on how to setup docker, pi hole, portainer or the likes.
ㅤ
Explanation & Goal
What’s the goal of this whole project? And how does Teddycloud work at all?
Well, an unmodified Toniebox is communicating with the official Toniecloud (by Boxine) for example to download any audio content (besides other things). So when you put a Tonie on the box, the real content of the audiobook will be downloaded from the Toniecloud (once) and is stored on the Toniebox for offline listening. The communication between the Toniebox and the Toniecloud takes place on a secured HTTPS connection, so certificates are needed on both sides (server/client). Without going too much into technical details, this is a simplified overview:
Now think of our self-hosted Teddycloud as a man-in-the-middle between the Toniebox and the Toniecloud. So at the end of this tutorial, the Toniebox won’t communicate with the Toniecloud/Boxine anymore but only with the Teddycloud. The Teddycloud itself needs to pretend to be a real Toniebox in order to be allowed to communicate with the original Toniecloud. And in order to achieve this, we need to extract the client certificates from our Toniebox and store them in Teddycloud so that from now on our Teddycloud looks like a real Toniebox from Boxine’s point of view. Without the client certificates, the original cloud won’t let Teddycloud download any content and not even establish a coummunication.
As a last step, the Toniebox needs to communicate with our new Teddycloud and this also needs to take place in a secured HTTPS way. That’s why we have to use a (self-generated) CA certificate on the Teddycloud Server and this certificate has to be known by the Toniebox as well (because never trust a stranger). So we need to replace the original CA certificate (from Boxine) with our self-generated one of the Teddycloud. Technically with the custom bootloader and the available patches we may run both certificates on the toniebox. The custom bootloader allows to simulate original firmware behavior and load the same image like the original firmware would, but with patches applied.
In addition to that, we run the toniebox with a patch that changes the original domains to a non-public domain that resolves to our teddycloud instance.
Tools
- a PC with Python >= 3.6
- a UART programmer for example a FT232RL
- connectors
- Refer to the wiki and use either a Tag Connect TC2050-IDC-NL; PCB Clip 1.27mm 5 Pin Double Row or just some 0.35 mm resistor clip offs
- (optional) multimeter
Preparation & Setup
Toniebox:
If your Toniebox is brand new, please connect it to your WiFi and so that the latest software update can be installed. Tutorial, you don’t need a tonies account for that.
Install required software:
In this example I will use a windows machine where I connect a UART programmer and a virtual machine running ubuntu, that runs my docker instance. I didn’t want to passthrough the programmer to the VM in order to not an additional layer of complexity. Probably it would have been fine.
I will not differentiate between the current directory on the windows machine and the linux machine, if you run a similar setup I assume you know how to move files between the two of them (scp
, a smb share, …)
- Download python with the UI installer, check to add python to PATH
- Install git; add to path if you want
- (optional) install pip, for me it was already included with the python installation
- Install cc3200tool, depending on whether you added git to PATH either use the command line or launch git cmd. Then enter
pip install git+git://github.com/toniebox-reverse-engineering/cc3200tool.git
For me, it did not resolve and I had to change it to
pip install git+https://github.com/toniebox-reverse-engineering/cc3200tool.git
Now continue on the machine you want to run docker on. For me it’s a VM on my server:
- install docker and docker compose. You may use some container management software like portainer, this may introduce another layer of complexity not needed when just deploying teddycloud.
- install Teddycloud
Create a folder and insert the following content inside a file namedocker-compose.yml
services:
teddycloud:
container_name: teddycloud
hostname: teddycloud
image: ghcr.io/toniebox-reverse-engineering/teddycloud:latest
ports:
- 80:80 #optional (for the webinterface)
- 8443:8443 #optional (for the webinterface)
- 443:443 #Port is needed for the connection for the box, must not be changed!
volumes:
- certs:/teddycloud/certs
- config:/teddycloud/config
- content:/teddycloud/data/content
- library:/teddycloud/data/library
- firmware:/teddycloud/data/firmware
- cache:/teddycloud/data/cache
restart: unless-stopped
# needed if using macvlan
# networks:
# - myteddycloud-creation
volumes:
certs:
config:
library:
firmware:
cache:
content:
# needed if using macvlan
#networks:
# myteddycloud-creation:
# external: true
Important:
If you’re not deploying teddycloud on a fresh machine / the machine is already used for something else, you may already be using the needed ports for other applications.
From what I gathered teddycloud requires to not be used with a reverse proxy. I used portainer to create a macvlan network.
This video (in german) explains it very well. Basically you can follow along starting at 5:43. If someone knows a good video in english, please comment. I will assume you have some basic understanding of docker, so hopefully you will be able to follow along.
Optional:
Instead of creating volumes you can also bind mount via
/some/path/on/host/library:/teddycloud/data/library
/some/path/on/host/certs:/teddycloud/certs
and omit the corresponding volumes. For me it’s easier to have access to these folders via my main maschine (over samba share) rather than going into my VM, that is running docker.
ㅤ
Connect flash chip with programmer
We have to open the box and obtain the plain mainboard without any connected cables attached. The process is the same as for ESP32 boxes like shown in this video (starting 14m58s): https://youtu.be/JpMRyshgy9o?t=899
Use an appropriate tool (or used two small screwdrivers) to release the battery connector. You don’t want to pull out the thin cables!
Be aware that the board is connected to the RFID reader with 6 pins at the bottom right side (the opposite side of the headphone jack)! So when trying to remove it, make sure to push it upwards (to the top) to avoid bending these pins by accident.
Now it’s time to make the connection to the debug port. As mentioned earlier I opted for the resistor clip offs method. I just used pliers to clip of the pins of a few resistors I had lying around.
@baumeisterde soldered the connections and used a female pin header.
I carefully placed my pins and used a multimeter to ensure connection / no shorts:
and hot glued it afterwards to make sure they don’t move during flashing. This was the easiest method for me. More expensive / more elaborate methods do exist as stated before. I used crocodile clamps and jumper cables to connect to the UART programmer.
ㅤ
Read, patch & write the certificate/firmware
Make sure your UART programmer runs at 3.3V! Measure with a multimeter to make sure.
Connect the UART programmer via USB to your computer. The green LED of the Toniebox mainboard should be constantly green (no flashing/blinking). If that’s not the case, your connections are most probably not sitting correctly. Before you try it again, unplug the programmer first!
I additionally supplied power to the toniebox (after I checked the programmer is connected correctly) via the charger.
All steps are taken from the wiki.
I try to streamline the process as much as possible. Basically we will perform the following steps:
- Extract certificates from toniebox and place them in teddycloud
- Flash certificate from teddycloud
- Along the way we will install the custom bootloader
For a better readability I chose to hide all steps in a details box so you don’t get overwhelmed with all the commands. Expand each step to follow it:
1 Backup
Open a terminal and navigate to a folder you want to work in and enter (check your paths!)
cc3200tool -p COM3 read_all_files ExtractedFromBox/ read_flash backup.bin
I will refer to the full path of your current directory as /currentDir in the future.
Make sure you selected the right COM port and if your UART programmer has a DTR pin use --reset dtr
before each command (cc3200tool -p COM3 --reset dtr ...
). Otherwise you need to briefly connect RTS to GND before each command.
For me, there were some files that did not exist on the box, thus the command exited with an error and never properly created the backup.bin.
I recommend going
cc3200tool -p COM3 read_all_files ExtractedFromBox/
cc3200tool -p COM3 read_flash backup.bin
Verify your results! Make sure backup.bin is not 0 kb.
2 Get the server certificate and upload client certificates
2.1
Copy the server certificate with a method of your choice. I like to work with the host paths:
Get your volume paths:
docker inspect -f '{{range .Mounts}}{{ if eq .Type "volume" }}{{println .Source }}{{ end }}{{end}}' teddycloud
Output:
/var/lib/docker/volumes/teddycloud_content/_data
/var/lib/docker/volumes/884******4bf/_data
/var/lib/docker/volumes/teddycloud_firmware/_data
/var/lib/docker/volumes/teddycloud_library/_data
/var/lib/docker/volumes/teddycloud_certs/_data
/var/lib/docker/volumes/teddycloud_config/_data
/var/lib/docker/volumes/teddycloud_cache/_data
So the certificates of Teddycloud are stored in
/var/lib/docker/volumes/teddycloud_certs/_data
on the host system.
Save your certificate.
sudo cp /var/lib/docker/volumes/teddycloud_certs/_data/server/ca.der /currentDir/server/ca.der
Refer to this post for an explanation and alternative.
2.2 (optional)
If your machine running docker (dockermachine) is not the same as the one you connected the UART programmer (UARTmachine) to, you need to transfer the files between the two systems.
Assuming you connect to your machine running docker via SSH, you could use scp
to transfer the files or you work in a shared directory (samba share for example). If you don’t need an explanation or don’t work with two machines, proceed with 2.3.
For scp
you need openSSH, install that on your machines if they don’t ship with it.
Example using scp
, indicating on which machine the command is executed:
# Since we need elevated privileges to access /var/lib/docker we need to copy the file to a directory we can access without sudo
name@dockermachine:~$ sudo cp /var/lib/docker/volumes/teddycloud_certs/_data/server/ca.der /dirForTransfer/server/ca.der
# Now we download the file to our UARTmachine
name@UARTmachine:~$ scp username@dockermachine:/dirForTransfer/server/ca.der /currentDir/server/ca.der
2.3
Depending on your paths you know should have something like this in your present working directory (where you started cc3200tool):
currentDir
│ backup.bin
├───ExtractedFromBox
└───server
2.4
Now upload the client certs to teddycloud:
sudo cp -r /currentDir/ExtractedFromBox/cert/. /var/lib/docker/volumes/teddycloud_certs/_data/client/
Newbie frienldy: Or use the webGUI of your teddycloud instance:
Navigate to http://IP.OF.TEDDY.CLOUD/web/settings/certificates and upload:
2.5 (optional)
Example as shown in 2.2 using scp
, indicating on which machine the command is executed:
# Copy the client certificates to the docker machine
name@UARTmachine:~$ scp -r /currentDir/ExtractedFromBox/cert/. username@dockermachine:/dirForTransfer/client/
# Since we need elevated privileges to access /var/lib/docker we need to copy the file from our temporary transfer directory we just uploaded to
name@dockermachine:~$ sudo cp -r /dirForTransfer/client/. /var/lib/docker/volumes/teddycloud_certs/_data/client/
3 Flash c2.der
cc3200tool -p COM3 write_file server/ca.der /cert/c2.der
Make sure you selected the correct path to the ca.der you extracted from teddycloud.
4 Follow the installation for the bootloader
This is well explained in the wiki so please refer there
4.1
Download the bootloader here.
Unzip and you get two folders: sd and flash.
4.2
First of all you need to copy your just backuped original mcuimg.bin (original bootloader) from your toniebox to a different location (flash:/sys/pre-img.bin) to boot it with the HackieboxNG Bootloader later on. Please don’t confuse the mcuimg.bin (ofw bootloader) you are going to dump with the mcuimg.bin within the hackiebox zip package. (/flash/sys/mcuimg.bin)
We already made a full backup so we can find mcuimg.bin under
/currentDir/ExtractedFromBox/sys/mcuimg.bin
since you should still be running cc3200tool from that directory write the file to the toniebox:
cc3200tool -p COM3 write_file ExtractedFromBox/sys/mcuimg.bin /sys/pre-img.bin
and install the preloader:
cc3200tool -p COM3 write_file flash/sys/mcuimg.bin /sys/mcuimg.bin
the path depends on where you placed the files from the bootloader.
4.3
We are done using cc3200tool. Personally I would disconnect power from the box now and disconnect the programmer’s USB connection so the box has no power. Now remove the SD card. There is some glue in front of it. Clean it up and then you can push the metal cover slightly forward and then pull it up. Then you can remove the SD card.
Copy over all the contents of the sd folder to the sd card of the toniebox. Copy over the original bootloader (mcuimg.bin from your backup) to the first ofw slot sd:/revvox/boot/ng-ofw1.bin . Now the HackieboxNG bootloader will instantly boot the original bootloader and run the original firmware.
Do not create a sd:/revvox/boot/ng-ofw2.bin When selecting ofw2 as the default / or starting it manually, it will use ng-ofw1.bin and apply the patches. See below.
I opted not to use the custom firmware, however in order to avoid having to disassemble the box again in the future I download the firmware from here.
And followed this step from the readme:
First of all you need to create “/revvox/web” on your sd card (subdir revvox should be already there if you have successfully installed the sd bootloader) and copy over the content of the /web/ directory of this repository. The same applies to the “/revvox/audio” directory for WAV-playback during the battery test. In addition you have to copy your cfw image to your selected slot(s) on the sd card. (ex. “/revvox/boot/ng-cfw1.bin”)
In order to have a second copy of the cfw according to the readme, I also placed it under /revvox/boot/ng-cfw2.bin. I didn’t boot it afterwards, refer to the wiki for further instructions.
This should give you the following structure:
sd:
|---revvox
| |---boot
| | |---ng-cfw1.bin (optional)
| | |---ng-cfw2.bin (optional)
| | |---ng-ofw1.bin
5 Edit ngCfg.json
We are going to make some edits to our file on the SD card we just copied.
"ofw2": {
"checkHash": true,
"hashFile": false,
"watchdog": true,
"ofwFix": true,
"ofwSimBL": true,
"patches": ["altCa.305", "altUrl.tc.fritz.box"]
Choose whether to use the tc.fritz.box patch or the altUrl.305 patch and choose the right patch for you under “patches”.
I also chose to always boot the ofw with applied patches so ofw2:
{
"general": {
"activeImg": "ofw2",
This is well explained in the wiki so please refer there.
Since i personally used the altUrl.305 patch I added local DNS entries in my pi hole instance for
prod.revvox and rtnl.revvox. Since there’s a multitude of options on how to achieve custom DNS entries I will not explain this step in detail.
Pihole is set as the DNS resolver in my fritzbox so all devices get assigned my pihole instance as a DNS server.
6 Reassemble
Disconnect everything and reinsert SD card in the toniebox. Now you can connect the speakers and ears and battery again.
You can fire up the box now and see if it’s working as intended. If everything works you can reassemble the box completely.
You’re done - you should now be able to use your own teddycloud.
7 Optional
Using the current version tc_v0.6.2 will lead to the following error in your logs:
ERROR|tls_adapter.c:0189:read_certificate| Failed to open '/teddycloud/certs/client/78dXXXXXX12fd/ca.der' for cert type detection
ERROR|tls_adapter.c:0376:load_cert| Loading cert '/teddycloud/certs/client/78dXXXXXX12fd/ca.der' failed
ERROR|tls_adapter.c:0189:read_certificate| Failed to open '/teddycloud/certs/client/78dXXXXXX12fd/client.der' for cert type detection
ERROR|tls_adapter.c:0376:load_cert| Loading cert '/teddycloud/certs/client/78dXXXXXX12fd/client.der' failed
ERROR|tls_adapter.c:0189:read_certificate| Failed to open '/teddycloud/certs/client/78dXXXXXX12fd/private.der' for cert type detection
ERROR|tls_adapter.c:0376:load_cert| Loading cert '/teddycloud/certs/client/78dXXXXXX12fd/private.der' failed
INFO |tls_adapter.c:0390:tls_adapter_init| Loading certificates...
As was explained to me by @0xbadbee teddycloud will use the certificates under /teddycloud/certs/client/
as a fallback so everything should be working.
If you want to resolve the issue you can create the directory 78dXXXXXX12fd
(UID of your toniebox) yourself.
For example (choose any other way you see fit) either find the host path for the docker volume and copy the certificates yourself also in /teddycloud/certs/client/78dXXXXXX12fd/
or connect to the container and do it within the container.
Find container name with
sudo docker ps | grep teddy
sudo docker exec -it teddycloud bash
inside the container do:
cp /teddycloud/certs/client/private.der /teddycloud/certs/client/dcda0c002b68/private.der
repeat for the other two and then exit
.
Next reboot it shouldn’t be a problem anymore.
Thank you @marco79cgn for allowing me to copy large portions of your cc3235 guide!
If you have any feedback, questions, corrections feel free to let me know!