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.