The Internet of Things on AWS – Official Blog
MQTT with TLS client authentication on port 443: Why it is useful and how it works
The AWS IoT Core service now allows you to connect devices using MQTT with TLS client authentication on port 443. Previously this combination of protocol and authentication mechanism was only supported on port 8883. So what’s the big deal? Read on to learn more about how this feature makes it easier to connect your devices or skip to the final section to learn how you can start taking advantage of it today.
443, 8883 – What’s the difference?
TCP connections are typically associated with a combination of IP address and port number. This immediately raises the question of which port number to use to ensure that your application can communicate with other 3rd party applications. To solve this problem, the Internet Assigned Numbers Authority (IANA) maintains a mapping of TCP and UDP port numbers to various messaging protocols that have registered with the organization. While this is not a canonical list, these standards are widely adopted, especially for more popular protocols. A quick search of their database shows that port 443 is the registered port for HTTP over TLS (i.e. internet traffic) and 8883 is the registered port for MQTT over TLS. AWS IoT Core complies with these standards as much as possible (see here), but as we have learned from our customers, there are scenarios where it makes sense to deviate from them.
Corporate firewalls and even some home routers often restrict inbound and outbound traffic to be transmitted over a small range of TCP ports. This is done as a security measure to limit the attack surface for possible cyber attacks. Standard ports for things like HTTPS traffic (port 443) are left open but others that are used for less common protocols, such as MQTT (port 8883) may be intentionally blocked. If you are manufacturing IoT devices that will ultimately be used in IT environments that you do not control, this can cause serious headaches. For example, if you manufacture medical devices that are sold to hospitals around the country, you do not want to have to negotiate separately with each hospital’s IT department to open port 8883 in their firewall so that your devices can connect to your IoT application running on AWS IoT Core. It just so happens that there is a standard extension to the TLS protocol that can help with precisely this issue.
ALPN – One port to rule them all
Application Layer Protocol Negotiation (ALPN) is an extension to TLS defined by RFC 7301 that is supported by many of the most common TLS implementations. ALPN enables clients connecting to a TLS server to pass an extra parameter, known as a ProtocolNameList, as part of the ClientHello message during the TLS handshake. The ProtocolNameList is a preference ordered list of the application protocols that the client would like to use to communicate. As part of the ServerHello message, the TLS server selects one protocol from this list that will be used to transmit application data over the connection.
The full TLS handshake including the ALPN extension works as follows:
Client Server ClientHello --------> (ALPN extension & list of protocols) ServerHello (ALPN extension & selected protocol) Certificate* ServerKeyExchange* CertificateRequest* <-------- ServerHelloDone Certificate* ClientKeyExchange CertificateVerify* [ChangeCipherSpec] Finished --------> [ChangeCipherSpec] <-------- Finished Application Data <-------> Application Data * Indicates optional or situation-dependent messages that are not always sent.
AWS IoT Core supports a special ProtocolName, “x-amzn-mqtt-ca”, that enables clients to specify that they will be using MQTT with TLS client authentication. It is necessary to use this special value instead of just “MQTT” because in addition to signalling which application protocol the client will be using, AWS IoT Core also uses the ProtocolName to signal that it should send a CertificateRequest as part of the TLS handshake. If the client were to send a certificate without AWS IoT Core requesting it, the TLS specification dictates that AWS IoT Core should terminate the handshake.
How can I connect my devices on port 443 using MQTT?
- Ensure your device’s TLS client implementation supports the ALPN extension.
- Consult the manual to be certain, but this Wikipedia page provides a handy list.
- Amazon FreeRTOS source code supports the ALPN extension.
- Register your device with AWS IoT Core by creating, activating, and downloading a certificate or bring your own certificate.
- Configure the ALPN extension on your device with the “x-amzn-mqtt-ca” protocol*.
- Connect to AWS IoT Core on port 443.
*NOTE: Currently “x-amzn-mqtt-ca” is the only supported ALPN ProtocolName and it is only supported on port 443. The most up to date mappings can always be found on the Protocols page in the AWS IoT Core Developers Guide