Using Device Time to Validate AWS IoT Server Certificates
What Time Is It?
For most of us, finding out the current time is pretty easy; we can just look at our smartphone, our watch, or a clock on the wall – for a computer however, it’s not so simple.
To start with, not all computers can keep track of time in the same way. Many computers have a peripheral called a Real-time Clock (RTC) (most PCs fall into this category). An RTC works like a watch that the computer can read or set, and it keeps time even if the computer is powered off. However, an RTC can’t always be counted on to be accurate; it could be set to the wrong time due to user error, clock drift (running faster or slower than actual time due to environmental effects), a software bug, or because its battery has worn out. Because of this, the computer’s operating system will probably have another way to find the current time.
Network Time Protocol
The Network Time Protocol (NTP) is a network protocol for distributing time information over the internet. Many operating systems (e.g. MacOS, Windows, GNU/Linux) include an NTP client to keep the system (and the computer’s RTC, if it has one) time up-to-date by synchronizing with an NTP server. The device you’re reading this on probably uses an NTP client to know what time it is. On GNU/Linux for example, the NTP client is called ntpd.
Many low-cost IoT devices do not include an RTC since adding one can add cost and complexity to the design. Such devices will not have any idea what time it is when they’re powered on, and unless they have an NTP client and are connected to the Internet, they never will unless someone sets the time manually.
X.509 Certificates and the Validity Period
AWS IoT Core connections use Transport Layer Security (TLS). During the establishment of a TLS connection (called a TLS handshake), the server (in this case AWS IoT Core) will present a server certificate to the client. TLS certificates are in X.509 format and include a variety of information such as the organization’s name and location, domain name, a public key, the type of algorithm used to verify signatures, and a validity period. The validity period is specified as a pair of time values called notBefore and notAfter. Services like AWS IoT Core use limited validity periods (e.g. one year) for their server certificates and begin serving new ones before the old ones expire.
In order for the client to know that it is connected to AWS IoT Core, it must validate the server certificate. The validation process involves ensuring that it has been signed by a trusted Certificate Authority (CA), that the domain name matches the one the client has connected to, and that the certificate has not expired or has yet to be activated. This check is where the client’s concept of time becomes critical.
If the client doesn’t know the correct time, it won’t be able to evaluate the server certificate’s validity based on the values of notBefore and notAfter. In the worst case, it might reject a valid server certificate because it thinks it was created in the future.
Certificate validity checks are usually performed in a system library like OpenSSL or mbedTLS and it may not be clear why the check is failing unless your application closely examines the returned error code. In OpenSSL, for example, these failures will result in X509_V_ERR_CERT_NOT_YET_VALID or X509_V_ERR_CERT_HAS_EXPIRED errors.
Best Practices for IoT Devices
Failure to provide accurate time in an IoT device design could prevent it from being able to connect to AWS IoT Core. If you’re building commercial IoT devices, remember that your products may be stored for extended periods before being sold. Real-time clocks can drift during this time and batteries can get discharged, so setting time in the factory is not sufficient. For most systems, this means that the device’s software needs to include an NTP client and should wait until it has synchronized with an NTP server prior to attempting a connection with AWS IoT Core. If this isn’t possible, the system should provide a way for a user to set the device’s time so that subsequent connections can succeed.
Finding an NTP Client
If you’re developing for an IoT device which runs GNU/Linux, there’s a good chance that the distribution you’re using already includes and starts ntpd. If you’re developing for a lightweight RTOS like Amazon FreeRTOS, you may need to find a small NTP client to port to your platform.
Configuring the NTP Client
Once you’ve provided an NTP client to your IoT device software, you’ll need to configure it so that it receives time updates from an appropriate NTP server. The proper NTP client configuration depends on your use case and is beyond the scope of this article; for more on this topic, we recommend starting with the excellent documentation provided by the NTP Pool Project. If you are building commercial IoT devices, please pay particular attention to the Information for Vendors on their project page.
In order for a device to validate the server certificate presented by AWS IoT Core for an MQTT connection, the device’s time should be within some reasonable distance of the server’s time, e.g. no more than a few hours. Devices connecting using WebSocket/SigV4 authentication have an additional and more stringent requirement on the server side and must be within 15 minutes of the server’s time.
Alternatives to NTP
Not all embedded devices may be able to use an NTP client. In these cases, devices will need a low-drift RTC as well as a method to set the time. Examples might include a front panel or local web interface which allows the user to set the time, or a mobile application which connects to the device over Bluetooth or Wi-Fi and sets the device time to the smartphone time.
TLS and X.509 certificates provide a secure foundation for building IoT systems, but they require that servers as well as clients know what time it is in order to function properly. Make sure your IoT devices always have the correct time before attempting to connect to AWS IoT Core or other TLS services which use server certificates.