Tuesday, December 31, 2019

Setting up TLS Communication between Embedded Devices


It`s time to write again. This time it`s about setting up TLS communication between embedded devices. When I tried to set up TLS communication between the two devices, I had to implement my own Provisioning set up. During that time, I tried to look up the internet to get some help, unfortunately, not much information is available there related to that. There were a few nice articles which helped me finish the work. So, I decided to write about what I had done as it would help me in the future if I had to do the same task again, if not useful to any other newbie like me.


My target was based on embedded RTOS, So I had to port the mbedTLS library to my platform which was embOS + HCC TCP/IP Stack. It`s not very difficult to port the mbedTLS as implementing few wrapper functions around Socket connectivity functions is enough to get the basic TLS Operation. If you want to use your target`s on-chip peripherals for cryptographic functions instead of MbedTLS library functions, you may need to implement a few more interface functions.


To get the knowledge about porting the MbedTLS library go through this below link as it has enough information related to that.



In short, for basic TLS functionality implementing your own net_sockets.c and replacing the existing implementation is enough. I`m not going to write about it as it varies depending on the TCP/IP stack being used and is quite easy compared to porting the TCP/IP Stack.


Let`s directly jump into our focus point which is about setting up the TLS Communication. I hope you already know about the basics of TLS, if not please go through the link provided at the end of the article first. To establish the TLS communication first, we need to set up provisioning as one of the fundamental concepts of TLS is about verifying the validity of the other end with whom we are talking. In fact, during the initial handshake itself that will happen. In our example for simplicity only the server`s certificate will be verified. It`s best to verify both the server and the client in real-time embedded devices.


As the first step in provisioning, we need to create the Certificate Authority that can give certificates to the end nodes to attest to the legitimacy of the end node to which the certificate belongs. OpenSSL is used for our demonstration. To do our task we can leverage the script provided by OpenSSL instead of commands as it will make our life easy.


To make the life much easier ( and for the safety of our host system ), copy the CA.pl ( usually resides in usr/lib/ssl/misc ) script and openssl.conf ( usually resides in usr/lib/ssl/ ) files to the directory where you want to generate the certificate. Edit both the files as per your requirement. For example, you might want to increase/decrease the certificate validity time or modify the number of bits used for RSA Key, etc.


Once you are done, enter the below command in the terminal from the same path CA.pl and openssl.conf are copied.

./CA.pl -newca


Enter all the necessary information about the certificate authority. If you don`t want to type all these during the certificate generation, you can edit the CA.pl and openssl.conf to provide all the information, in that case, you can just press enter as the default value given in script and configuration file will be used for Certificate generation. The command will create the root certificate authority which can be used to sign our certificates.



Now the certificate authority is ready. We need to create the Signing request, to do that enter the following command,

./CA.pl -newreq


Enter all the necessary information about the server. Please note that all these information are related to the server and will be in the subject field of the server certificate, while all the information provided above ( in newca command ) will be in the Issuer field of the server certificate.



Finally, we need to use the CA to generate the Signed Server certificate, to do that enter the following command,

./CA.pl -sign



Use the Credentials ( Pass Phrase ) of the Certificate authority to sign. Ensure all the presented information matches the information of the Server certificate and the validity of the certificate. Once everything is okay proceed for signing.


In the end, the server certificate will be generated in the same directory CA.pl is located with the file name of newcert.pem and the private key of the server certificate will be with the file name of newkey.pem.


Now we can use these in our embedded target for TLS Communication. I assume you`re already familiar with the examples provided by MbedTLS example ( ssl_server and ssl_client ). I`m going to mention only the functions which need to be modified for our task. Please modify other configurations as per your requirement.


We don`t need the file system to store the certificate and private key, we can just store the certificate and private key in character array format to feed the MbedTLS library.


Character string starting from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE----- should be stored in an array for the Server certificate and the root certificate, likewise for the private key, the string starting from -----BEGIN ENCRYPTED PRIVATE KEY----- to -----END ENCRYPTED PRIVATE KEY----- should be stored in an array.


In server-side we need to provide the server certificate followed by the root certificate, in case if there are intermediate certificates between root and server certificates ( not present in our example, but in real-time it`s good to have ), then those intermediate certificates should also be provided in the order. We need to pass the certificates to the mbedtls_x509_crt_parse function as shown below on the server-side.

mbedtls_x509_crt_parse( &sX509ServerCertificate, (const unsigned char *) u8ServerCertificate, sizeof( u8ServerCertificate ) );

In which u8ServerCertificate is the array that is initialized with the server certificate string.


Like above, Certificate of Root Authority should also be passed to the mbedtls_x509_crt_parse function as shown below,

mbedtls_x509_crt_parse( & sX509ServerCertificate, (const unsigned char *) u8CaCertificate, sizeof( u8CaCertificate ) );

In which u8CaCertificate is the array which is initialized with the certificate string of Root Certificate Authority.


To provide the private key of the server to the SSL Configuration, we need to pass the array which has the private key to the mbedtls_pk_parse_key function as shown below,

mbedtls_pk_parse_key( &pkey, (const unsigned char *) u8ServerPrivateKey, sizeof( u8ServerPrivateKey ), NULL, 0 );


That`s all what we need to configure on the server-side, on client-side we just need to configure the trusted root certificate, that can be achieved just like above using the same mbedtls_x509_crt_parse function. That`s all you need for basic TLS communication, you can just execute both the server and client applications, which will be talking with each other securely with TLS.



Please refer to the below link for more details on TLS.



No comments:

Post a Comment