This is post 7 of the series/tutorial. In case you have not gone through the other posts, you can do so now.
In the previous post (post #6), we got mbedTLS working and it delivered content to us from a server using SSL/TLS. However, in the code, you should have noticed a line saying that in real life we should bail out when the certificate verification fails, see it here. Also in the logs, you must have seen a section with errors like the one below.
. Performing the SSL/TLS handshake... C:\Keil_v5\ARM\PACK\ARM\mbedTLS\1.0.0\library\ssl_tls.c:4353: x509_verify_cert() returned -9984 (-0x2700) ok . Verifying peer X.509 certificate... failed ! The certificate Common Name (CN) does not match with the expected CN ! The certificate is not correctly signed by the trusted CA
The certificate Common Name did not match with the expected CN
The certificate obtained by the client from the server had a number of enabled domains
*.mbed.org and maybe more. You can open tls.mbed.org in your browser and observe the certificate by clicking the green part of the address bar. In code, however, we set the expected name to a static name ==mbed TLS Server 1== as shown here. This is wrong and needs to be changed to the appropriate hostname. When I encountered this problem, I though it resulted from using a wildcard certificate, but it was not. More about wild card certificates here and here. By the way, they are quite expensive. The fix is shown in commit 99bef50.
The certificate is not correctly signed by the trusted CA
All TLS certificates have to be signed by trusted a certificate authority (CA) like Comodo, RapidSSL, StartSSL, GoDaddy etc. Each of the CA certificates would be installed on the client machines such as your computer, so that when a certificate is sent, it would determine if it knows the issuing authority. Your operating system would come with those certificates of trusted authorities. In this case, we have an RTOS with limited memory and we need not have all the CA certificates inside a normal operating system such as Windows. We need to add those we surely need. The certificate used at tls.mbed.org is signed/issued by GlobalSign (GMA Internet Group). You can check in your browser as mentioned earlier. We need the root certificate from them so that we may add it to our code. The root certificate can be obtained from here. Fixing this to the code is shown in commit 2c0bb84.
My output log now looks like this:
. Seeding the random number generator... ok . Loading the CA root certificate ... ok (0 skipped) . Connecting to tcp/tls.mbed.org/443... ok . Setting up the SSL/TLS structure... ok . Performing the SSL/TLS handshake... ok . Verifying peer X.509 certificate... ok > Write to server: 18 bytes written GET / HTTP/1.0 < Read from server: 165 bytes read HTTP/1.0 200 OK Date: Sun, 28 Feb 2016 14:20:43 GMT Connection: close Content-Type: text/html Last-Modified: Tue, 19 Jan 2016 14:17:43 GMT Content-Length: 0 C:\Keil_v5\ARM\PACK\ARM\mbedTLS\1.0.0\library\ssl_tls.c:6421: mbedtls_ssl_read_record() returned -30848 (-0x7880) C:\Keil_v5\ARM\PACK\ARM\mbedTLS\1.0.0\library\ssl_tls.c:2838: mbedtls_ssl_flush_output() returned -80 (-0x0050) C:\Keil_v5\ARM\PACK\ARM\mbedTLS\1.0.0\library\ssl_tls.c:3944: mbedtls_ssl_write_record() returned -80 (-0x0050) C:\Keil_v5\ARM\PACK\ARM\mbedTLS\1.0.0\library\ssl_tls.c:6761: mbedtls_ssl_send_alert_message() returned -80 (-0x0050) Last error was: -30848 - SSL - The peer notified us that the connection is going to be closed
Optimization 1: Remove DTLS
For our tutorial, we are using TCP-dependent communication and thus we can remove support for DTLS in our code. DTLS is the TLS for UDP-dependent communication such as CoAP. It is accomplished in the mbedTLS_config.h file. It saved me 7736 bytes (7.55kB) of flash and 56 bytes of RAM. See commit e9229610.
Optimization 2: Remove support for SSLv3
SSLv3 is said to have huge bugs and for security reasons I choose not to support it from now and further into the future. Furthermore, the IoT servers we'll use were built or updated more recently. See commit cde242b8.
Optimization 3: Do not proceed if we cannot verify the certificate
Normally, a browser requires you to explicitly allow it to proceed when it determines a certificate as invalid either due to expiry, wrong host or untrusted CAs. In an IoT device, we cannot ask for user input every time. I consider it a good practice to not proceed if we cannot verify the certificate. This is shown in commit 46808093.
The downside of this practice is that you need to add all possible trusted CAs on your IoT device so that it is not affected when you change the CA of the certificate on your server. This has already been solved by operating systems. They have a place where certificates for trusted CAs are stored. For IoT devices, we can utilize the same mechanism by adding some storage possibly exposed as a USB Mass Storage device. Alternatively, we can issue updates over the air (OTA) to update the list of trusted CAs.
Other unimplemented optimizations
Use hardware acceleration where available like on STM32F439x/F207x/F407x etc. You can also use an external encryption IC from Atmel if you are up to the challenge of such kind of work. Explore your entropy sources and determine if they are enough to form proper randomness for security reasons. As per our code, the tick timer is used to provide entropy. Most STM32 microcontrollers already have an inbuilt RNG (Random Number Generator) module, which is a good source of entropy. I hope to do a blog on entropy one day.