Skip to content

Integrating the Tapkey Mobile SDK for Embedded Devices

Overview

The Tapkey Mobile SDK for Embedded Devices is a set of libraries, examples and documentation intended to be used for implementing embedded devices that can act as clients to Tapkey locking devices. Most notably it allows triggering lock/unlock actions from an embedded device via Bluetooth.

The libraries and sample code are written in pure ANSI C to allow a maximum of portability. The client libraries have especially been designed to run resource-constrained, low power devices.

In contrast to the Tapkey Mobile SDKs for Android and iOS, the one for Embedded devices does not expect the device it is running on to have online connectivity to the Tapkey Trust Service. This has several consequences:

  • The implementor must take care of retrieving the required artifacts (i.e. keys, etc.) via the Tapkey Mobile API.

  • There's no automatic mechanism for rolling keys on a regular schedule. While keys issued to other devices are usually only valid for a limited period of time and renewed automatically, in case of embedded devices the implementor must take care of this procedure. Keys must either be configured to have an unrestricted lifetime or the implementor must take care of renewing keys before they expire.

  • No automatic syncing of the locking devices's clock. When other mobile devices detect that a connected lock's clock is wrong, it will automatically relay the connection to the Tapkey Trust Service, which will take care of synchronizing the lock's clock. This procedure is not supported on embedded devices. As keys that are limited in their lifetime require the locking device's clock to be correct, it's up to the implementor to take care of syncing the it. As an alternative keys may be configured with indeterminate lifetimes. Such keys don't require the lock's clock to be properly set and therefore simplifies the overall setup. However, unrestricted keys have several downsides (see following chapters).

  • No automatic forwarding of log data: While the Tapkey Mobile SDKs for Android and iOS automatically relays the latest log events from a locking device to the Tapkey Trust Service when executing a command, this is not supported on embedded devices.

Key Lifetime

Keys issued to mobile devices are usually limited in their lifetime and renewed (rolled) on a regular basis using the mobile's internet connectivity. As embedded devices often don't have their own internet connectivity, keys may also be issued with indeterminate lifetime. This removes the need for automatic key renewal and also removes the requirement for the lock's clock to be correct. However, there are some downsides to unrestricted keys:

  • Revoking such keys can only be achieved by adding them to the affected lock's revocation list. As the keys don't ever expire, they need to stay in the RCL forever. The RCL for this class of devices on the other hand is short and may hold only a single entry. This implies, that revocation of such a key may implicitly revoke all other keys for the same lock and the same revocation class as well. In the end, revoking a single indeterminate key for an embedded device may render the keys of all other embedded devices for the same locking device useless and require manually renewing all of them.

Keys for other types of mobile devices or for cards have different revocation classes and their revocation therefore doesn't interfere with the keys of embedded devices.

  • If an embedded device is compromised and a key is extracted, then it's only possible to revoke the key via mechanisms of the revocation list, causing the issues discussed above.

  • The implementor must take special security precautions to prevent those such keys from being extracted from the embedded device.

Configuring a key for indeterminate lifetime consists of following steps:

  • Request Tapkey support to configure the affected owner account to allow for overriding the key lifetime.

  • When registering the mobile device via the Tapkey Mobile API, specify a device type that is configured for indeterminate key lifetime. The device type is named by Tapkey.

  • When creating the grant, specify a key lifetime of -1, which indicates an indeterminate key lifetime.

  • It's suggested to specify a mobileDeviceRef for grant with indeterminate lifetime. This ensures that the Grant is only used on mobile devices specifying the same value and prevents the key from being installed on different kinds of devices like smartphones.

Implementation Steps

Using this SDK usually consists of following steps:

  • Create a user in the Tapkey Trust Service representing the embedded device.
  • Grant the user access to the locking device(s) in question.
  • Register the embedded device as a mobile via the Tapkey Mobile API.
  • Query crypt artifacts (i.e. a key) from the Tapkey Trust Service, which usually comes in JSON encoding.
  • Transfer the artifacts to the embedded device and decode the JSON.
  • Configure the embedded device to listen for advertising locking devices.
  • Parse the received advertising data and filter for the expected lock ID.
  • Connect to found locking devices via Bluetooth.
  • Execute the desired command (usually TriggerLock) and wait for the response.
  • Disconnect from the connected device.

Querying a key via the Tapkey Mobile API

Creating a user

As any other mobile device, embedded mobile devices act in the context of a user. Grants are always issued to users, not to mobile devices. It's suggested to create an individual user per device.

Several authentication options exist, including

  • If the number of devices being managed is low and constant, then a client credentials user might be the way to go.

  • In cases of bigger installations with a dynamic number of devices, it might be more appropriate to manage those users via an external identity provider, which is connected to Tapkey. Users are then authenticated using the Token Exchange Flow.

Granting Access

Granting access to new users consists of two steps:

  1. Create a contact for the user via the PUT Contacts endpoint.

  2. Create a Grant via the PUT Grant endpoint that assigns an access permission for the given locking device to the given contact. See the Key Lifetime to learn about how to configure an extended or indeterminate key lifetime.

Registering the embedded device

Once the user has been created, the user can authenticate against the Tapkey Trust Service using the appropriate authentication flow. Make sure to request the register:mobiles handle:keys scopes.

Once authenticated, the mobile may be registered using the PUT /api/v1/Users/{userId}/Mobiles endpoint.

{
  "deviceId": "abcdefgh",
  "cloudMessagingKey": null,
  "mobileDeviceRef":"myCustomValue",
  "clientInfo": {
    "ptf": "Embedded",
    "app": "com.example.tapkeyclient",
    "ver": <value from tk_tlcplib_versionInt>,
    "apv": "<application version>"
  }
}

Querying the key

Once the mobile device has been registered, keys may be obtained for it using the POST /api/v1/Mobiles/{mobileId}/Keys/$/Request endpoint.

Using the key on the embedded mobile device

Parsing the artifacts

The crypt artifacts (the key) are returned by the Tapkey Mobile API in JSON encoded form. Many fields like the revocation list are represented as byte arrays which are encoded in Base64 format. It's up to the implementor to do the JSON decoding. However, there's functionality available in tk_mobile_api.h that allows transforming the decoded fields into structures as required by the subsequent functions.

Listening for Bluetooth GAP Advertisements

Locking devices advertise their lock ID via Bluetooth GAP advertisements. By listening to those advertisements, the devices of interest (i.e. having a certain lock ID) can be identified.

Tapkey locking devices advertise in one of two advertising formats: Version 1 or Version 2. A mobile client may listen to one or both of these formats. The following data is required in order to properly listen for advertisings. Find more details in tk_ble_gap_advertising_parser.h.

The data is part of the device configuration:

  • Advertising Format V1: The 128-bit Service UUID.
  • Advertising Format V2: The 16-bit Domain ID.

The file tk_ble_gap_advertising_parser.h provides functionality for parsing advertising frames and also for obtaining configuration regarding the expected GATT services and characteristics.

The result of parsing an advertising frame is the information, whether the frame matches the expected configuration and if so which lock ID is being advertised.

Connecting to a locking device

Once a locking device has been identified based on the advertised lock id, a connection attempt may be started, which usually involves the following steps:

  • Connect on Bluetooth LE layer
  • Reduce the connection interval as far as possible to reduce latency.
  • Request an updated MTU size. Usually an MTU size of 83 bytes is appropriate.
  • Discover services, i.e. discover the service and characteristics as indicated by tkMobileBleAdvertising_V?_getServiceConfig().

Executing the desired command

Once a connection has been established, it can be used to execute commands against the connected device via the following procedure:

  • Use tkMobileBle_init() to initialize the transport layer. Pass in functions that allow sending frames to and receiving from the locking device.
  • Use tkMobileBle_updateBleFrameSize() to update the established frame size (which is MTU size - 3).
  • Use tkMobileBle_handleConnection() to proceed to the next protocol layer. The function's handleConnection parameter takes a function of type tk_mobile_ble_handleConnection that implements the upper protocol layers.

  • In the handleConnection function passed in the previous step initialize the application layer via tkMobileInit().

  • Invoke tkMobileExecuteCommand() to actually execute the desired command. This function will take the key material and other artifacts as received from the Tapkey Mobile API.

Disconnect

Don't forget to close the Bluetooth connection.

System requirements

  • MCU like Cortex M0, Cortex M3, Cortex M4
  • Bluetooth GATT-enabled stack
  • ~40 kB of program space
  • ~16 kB of RAM