Thursday, May 9, 2019

CoAP support in Apache Camel

The Constrained Application Protocol (CoAP) is standardized in RFC-7252. It offers REST-like functionality over UDP for constrained devices in the Internet of Things. Apache Camel has had support for the CoAP protocol since the 2.16 release, by using the eclipse Californium framework. It offers support for using CoAP in both producer and consumer mode, and also offers integration with the Camel REST DSL. In this post, we will cover a number of significant improvements to the Camel CoAP component for the forthcoming 3.0.0 release.

1) DTLS support

The first significant improvement is that the CoAP component has been updated to support DTLS, something that necessitated a major upgrade of the californium dependency. CoAP supports TLS / UDP using a "coaps" scheme, something it is now possible to use in Camel. To see how this all works, take a look at the following github test-case I put together:
  • camel-coap - A test-case for the camel-coap component. It shows how to use the coap component with the Camel REST DSL + TLS.
It follows the same approach as the previous tutorial I wrote on securing the Jetty component in Camel:

It uses the Camel REST DSL to create a simple REST service on the "/data" path that produces an XML response when invoked with a GET request. The actual route is omitted above, it just returns a XML document read in from a file. Note the component of the REST DSL is "coap" and it uses a scheme of "coaps". When using a scheme of "coaps", we need to configure the relevant TLS configuration, something that is done by referring to a "sslContextParameters" bean, which in this case contains a reference to a keystore used to retrieve the TLS key. Note that when using a certificate for TLS with CoAP, an elliptic curve key is required - RSA is not supported.

On the client side, the test-case shows how to configure a Camel producer to invoke on the coaps REST API:

Note that a scheme of "coaps" is used, and that it refers to a sslContextParameters bean containing the truststore to use, as well as a specific CipherSuite (this is optional, I just put it in to show how to use it). As the logging output does not really show what is going on, here is the Wireshark output which shows that DTLS is in use:

2) Support for Raw Public Keys and Pre-Shared Keys

In the section above, we saw how to configure CoAP with DTLS by referring to a sslContextParameters bean, which in turn refers to keystores to extract private keys and certificates. This is one option to support DTLS. However we also have two other options instead of using certificates.

The first is called Raw Public Keys. This is when we may not have access to a certificate containing the (trusted) public key of the endpoint. In this case, we can configure TLS using a PrivateKey and/or PublicKey objects. Both are required for a service. The client needs to be configured with a trustedRpkStore parameter, which is an interface supplied by Californium, that determines trust in an identifier. If the service is configured with "clientAuthentication" of "REQUIRE", then the service must configure trustedRpkStore, and the client must also specify a privateKey parameter. Here is a sample code snippet from the Camel tests:

The second option is called Pre-Shared Keys. This is when we don't have access either to certificates or public keys, but have some symmetric keys that are shared between both the client and service. In this case, we can use these keys for TLS. Both the client and service are configured with a "pskStore" parameter, which is an interface in Californium that associates a (byte[]) key with an identity. Here is a sample code snippet from the Camel tests:

3) Support for TCP / TLS

A newer RFC (RFC-8323) extends the original RFC to add support for CoAP over TCP and Websockets. Camel 3.0.0 has added support for using CoAP over both TCP and also TLS over TCP. Websocket support is not currently available. RFC-8323 uses two new schemes for TCP, both of which are supported in Camel - "coap+tcp" for CoAP / TCP, and "coaps+tcp" for CoAP / TCP with TLS.  Only the certificate method of configuring TLS is supported, which works in exactly the same way as for DTLS above. Pre-shared keys and Raw Public Keys are not supported over TCP now, only UDP.

To see how it works, simply alter the configuration in the github testcase and change "coaps" to "coaps+tcp" (in both locations). Now run the test-case again and it should work seemlessly: