Continue from last week’s progress, I was feeding in hard-coded time data that is valid into bearSSL engine to pass the certificate date verification so that an SSL connection can start. This is definitely not a proper way to obtain the time, I did that just to make sure the bearSSL client actually works with a valid time data, to characterize the problem. So now, I am to get the actual time data from a public global time server. No worries, the mighty Harmony has got your back. Inside MHC, in TCP/IP stack, make sure “use SNTP client” is selected. This will get the board to fetch the current time from global time server every ten minutes (first it sends DNS request to resolve the default server name “pool.ntp.org”, the IP address of a few available time server is returned, then NTP request is sent to the time server). The retrieved time data (after adding the time passed in the transmission process) is synchronized with the timer on the chip then we have the time accurate to millisecond. A call to function TCPIP_SNTP_TimeGet(&Seconds, &miliSeconds) will return whether or not the call succeeds. But it always returns failure to me. Looking at Wireshark I can see the DNS request, the returned IP addresses of time server, the NTP request, but the time server did not reply to our request.
Dr. Shawn came and try to send the NTP request from the PC, the NTP server did not reply as well. So, it is a firewall issue, our firewall is blocking the reply. Dr. Shawn can poke a hole on the firewall to allow transmission but this also means our clients have to fix their own firewall to get it works, which is an issue already, and what if they don’t have the accessibility to configure the firewall? So, Dr. Shawn asked me if there is another way to pass the certificate verification without the time information. Actually, bearSSL do support a “known-key” mode which hard-code the public key in the certificate verification engine in advance instead of obtaining it from the server certificate, it skips all the certificate verification process and returns the stored public key directly. Hence, we do not need the time information to verify the certificate. In fact, the server does not need to send the certificate at all. The handshake engine will still check the signature to make sure the stored public key matched with the server private key before data transmission start, so it is acceptable security-wise. But people don’t usually do this because:
i) The certificate shall be verified to prove it is trustworthy.
ii) Public key shall be obtained from the server. With the hard-coded public key, it can only talks to the one server with the exact corresponding private key.
Though in our case,
i) We control both ends of the transmission, we trust our own server.
ii) The OTA application only needs to talks to one server, the one providing the firmware update. Store its public key and that’s it.
Thus, the “known-key” mode seems to be a legit approach for us. The only problem for me is that there is none working example provided but only some description on the webpage. Anyhow, let’s get started:
i) Instead of br_x509_minimal_context, the known-key certificate verification engine has type of br_x509_knownkey_context, with all the verification process (start_chain(), start_cert(), append(), end_cert(), end_chain()) that does nothing except get_pkey() that return the stored public key directly.
ii) Get the public key in type br_ec_public_key. BearSSL didn’t provide the tool to solely generate the C code for a public key, but a trust anchor does contain the public key. In /BearSSL/build directory:
./brssl ta <PEM file of server certificate>
This generates the trust anchor, take the public key inside, store it in type br_ec_public_key
iii) Initialise br_x509_knownkey_context by
br_x509_knownkey_init_ec(&knownkey_context, &public_key, usages) for the EC(Elliptic-curve cryptography) keys.
Here we feed in the public key and specify the allowed usage of this key. The usage include: BR_KEYTYPE_KEYX for key exchange and BR_KEYTYPE_SIGN for signature. To allow both, do a bitwise OR.
iv) Build a custom profile to replace br_ssl_client_init_full() , the sample is on custom_profile.c, set up the supported cipher suite, TLS version, PRF implementation, hash, key algorithm, signature, record handler, symmetric encryption, ghash and finally set up the known-key certificate verification engine with br_ssl_engine_set_x509().
After all the unavoidable trial and error I managed to get it works.
Then I get the bearSSL on PC to send out some dummy data, download it with bearSSL client on board, write them in flash memory, generate sha1 digest and do the checksum.
Previously, I have shut off the other threads (CORS & HID) to avoid confliction of code or problem in memory management, it’s time to turn them back on. After some little configuration of MHC, I try to run the bearSSL server in CORS and bearSSL client in OTA at the same time and surprisingly it works, wow that’s above my expectation (except of course the PUT request that downloads the bitstream can’t run simultaneously with firmware download in OTA as they both write to Flash memory).
On this Wednesday, Dr. Shawn brought us to TGV cinema to watch Mission Impossible Fallout. On Saturday, a lunch treat filled with his life stories and jokes. Oh man, what a week. He is that kind of person who motivates you with just the presence of himself. But time freaking flies, this is already my tenth week working in Aeste Works as an intern, two more weeks to go before I say my last goodbye, and I have to save the last week to prepare the documentation for all the things I have done so that the people who carry on with this project can catch up. So, technically speaking I have only one week left to get the real things done. Just as I thought my task is almost about to finish, on yesterday, Dr. Shawn assigned me one more thing, for the update of firmware on run-time, instead of duplicating the data stored in PFM2 to PFM1, swap flash, then run the new firmware (which cause half of the flash memory to be wasted and we can’t change the board configuration stored in BFM), I shall figure out another way that works with bootloader and utilize BFM. To be honest, I am not sure if I can finish this in one week, but I’ll try my best.