The Xedge C Code for Embedded Devices

Xedge transforms the Barracuda App Server into a versatile Lua development tool, offering an optimal starting point for anyone using the Barracuda App Server in an RTOS environment. Beyond development, the strength of Xedge lies in its adaptability for production systems. Keeping Xedge as part of your production system not only simplifies the end product, but also enhances its capabilities, allowing it to take advantage of the plethora of services Xedge provides. The Xedge Lua code can optionally be replaced with your own specialized Lua bootloader and final application as needed, while the Xedge's C code can typically be used 'as is' for your final product, but note that using Xedge in a production system adds value by offering seamless, integrated functionalities.

Xedge

Xedge's Lua application, which is embedded in the executable, is best visualized as Lua firmware. The Lua firmware is a compressed ZIP file stored inside the executable and made available to the Lua Virtual Machine via the ZipIo.

This document explains how to build the Xedge C code. Using Xedge is explained in a separate document.

Compiling Xedge

The following section includes generic build instructions. We provide two ready to use RTOS build projects you may download and use:

Include the following files in your build:

The file XedgeZip.c must be created by running barracuda/examples/xedge/make/BuildXedgeZip.cmd.

The file XedgeZip.c is a C array containing the zipped Xedge's resource files (Xedge.zip) and is mounted by the C startup code as a ZipIo and used by the Lua VM's required 'vmio'. We recommend studying the content of the produced ZIP file to get an understanding of the various resource files.

In addition to including the above files in your IDE/Makefile, add the required include path and #define directives as required by your platform. See the readme file barracuda/builds/[platform]/readme.txt for details.

The file system plugin barracuda/xrc/DiskIo/[platform]/BaFile.c is optional and may be included if you have a file system in the device and if a suitable plugin is found in barracuda/xrc/DiskIo/ directory. You must add #define NO_BAIO_DISK in your IDE/Makefile if you do not plan on using a file system. See the DiskIo documentation for details.

Enabling Additional Features

BAS Amalgamated (BAS.c) includes features that are by default not compiled. These features can be enabled by the following macros. The macros can be enabled on any platform, including RTOS, unless stated otherwise.

The following macros are required if you plan on using the Let's Encrypt plugin. The macros are pre-set for the following ports: POSIX (Linux/QNX), Windows, VxWorks, and INtime.

All porting layers, except POSIX and Windows, have the following pre-set:

The above construction makes Lua use integer only and excludes floating point numbers. To re-enable floating point, compile the code with:

See inc/arch/XXX/luaconf.h for details.

Xedge's Configuration File

Xedge keeps the configured application(s) and their state in a JSON file. This file is stored on the embedded file system if Xedge is compiled with file system support or in the browser using Web Storage if Xedge is compiled with #define NO_BAIO_DISK.

The LSP application(s) startup state differs between a device with and without file system support:

Note: When using the NetIo, make sure to start a Web File Server on your host computer prior to booting the embedded device.

Adding Lua Bindings

To access the device hardware via the embedded system's C code, custom Lua bindings must be added. See the getting started guide and advanced Lua bindings for how to create Lua bindings automatically or manually.

Time

When using a secure TLS client connection, such as HTTPS, or enabling the Automatic Certificate Management feature, the device must either have a clock with the correct time or fetch the time from the Internet using SNTP. The Barracuda App Server relies on the time returned by the platform-dependent function baGetUnixTime() defined in TargConfig.h. This header may also include baSetUnixTime(), which SNTP code can use when updating the time on a device without a clock. When updating the clock using SNTP, send the "sntp" event upon setting the time. See the Events below for details.

Events

Xedge features an event mechanism that allows simple events to be sent asynchronously from C code to Lua code. The Xedge Lua code includes the following global Lua function, which the C code can call to distribute events throughout the system:

function _XedgeEvent(eventname,...)

Lua code can subscribe to events, and the Lua callbacks are triggered when the C code calls _XedgeEvent. The arguments can be any value, with one exception: Xedge requires the "sntp" event to activate Automatic Certificate Management if the device does not include a clock. To activate the certificate management, the C code must call _XedgeEvent("sntp"); see time above for details.

See Send Events Via The Lua Thread Library for more information on how to call _XedgeEvent from C code.

Creating a Release Build

When development is complete and when you are ready to release the product, you will typically need to compress all of your Lua files into a single ZIP file. Here's a straightforward way to do it which is compatible with both Linux and Windows systems. This method also includes hidden files and directories that you might have in your project, like ".preload" and ".lua".

zip -r -9 ../device.zip ./

Once your development process is complete, you essentially have two main choices:

Creating an Xedge Release

Including the Xedge Lua application in your final release is the quickest way to move your project to production. This is because you can take advantage of all the features that Xedge offers. If you prefer, you can also choose to hide the Xedge User Interface (UI) to prevent end users from accessing it. Note that this option requires an embedded file system.

Here are the steps to use Xedge as a key component of your final product:

Preventing Users from Accessing the Xedge UI

If you want to restrict your customers from writing their own custom Lua applications, you can either prevent access to the UI by adding SSO authentication or remove the web-based Xedge UI completely in your application at startup. Here are the details on both methods:

Creating a Custom Release Build

This section applies to developers who want to completely avoid including the Xedge Lua code and resources in the final production system. However, note that by doing so, you will no longer be able to use the additional Lua APIs and features provided by Xedge.

You may create the final custom release when the development is complete. The recommended release method is to ZIP all resources together and then convert the ZIP file to a C array using the bin2c tool. Your web application stored in the ZIP file may then be compiled and linked with your firmware. If you have a file system, you may optionally store the ZIP file on the file system. In any event, our recommendation is to always use the ZipIo for deployed applications and not to store web pages directly on the embedded file system. The ZipIo is in most cases faster than fetching resources directly from an embedded file system.

Xedge's startup code xedge.c is designed for mounting an embedded ZIP file and to initially run the .config Lua startup script. You may use the file xedge.c "as is" for your release if you add the .config script we have prepared to the root of your application. The .config script opens the server's listening ports and loads the optional .preload script.

  1. Copy the .config script as explained above.
  2. Modify the .config script as needed.
  3. ZIP all files together and include any additional resources from the Barracuda App Server's resource directory or copy the resources from the original Xedge.zip file. Note, the ZIP file must not include the name of the top directory.
  4. Convert the ZIP file to a C array as follows: bin2c -z getLspZipReader your-zip-file.zip XedgeZip.c.
  5. Replace the original XedgeZip.c (Xedge's Lua code) with the file produced in step 4.
  6. Compile and link.

You may want to study the content of the original Xedge.zip prior to creating your own ZIP file.

Note that you may create any number of ZIP files and associate each ZIP file with a Barracuda Resource Reader, thus effectively creating an app for each ZIP file. You may also have part of your application read resources via a DiskIo if you, for example, want your customers to be able to modify or add LSP code. The Barracuda App Server is extremely configurable and you may assemble a server anyway you want.

soft Trusted Platform Module

A Trusted Platform Module (TPM) is a device security chip for storing encryption keys and ensuring system integrity. It enhances security through hardware-based encryption and system checks.

Xedge incorporates a sophisticated soft TPM, which, when properly configured, closely mirrors the security capabilities of a physical TPM chip. This integration ensures robust encryption and system integrity, offering a high level of security akin to hardware-based TPM solutions. The Xedge soft TPM streamlines security processes by removing the necessity for extra hardware, offering a simple yet efficient solution. However, it specializes exclusively in managing Elliptic Curve Cryptography (ECC) keys, focusing its capabilities on this advanced cryptographic system.

The soft TPM in Xedge enhances security through multiple layers, relying on additional measures like signed binaries and restricting firmware modifications to trusted sources. While these steps bolster security, the system maintains a reasonable level of security even without them. Here's a brief explanation of its operation:

The src/EncryptionKey.h file contains a binary random number of variable length, set by the product designer. This number, consistent across all firmware copies, is supplemented with extra entropy to generate unique keys for each device. A common method for this is utilizing eFuse registers. If the device has a true random number generator, the eFuse is programmed during the first power-up. In its absence, eFuse registers are configured during manufacturing.

The Xedge Lua firmware, embedded as a ZIP file within the device, contains exclusive Lua code not accessible externally. This code integrates random numbers generated by the C code at startup. From these, a pre-master secret is calculated. This secret forms the basis for generating multiple unique secrets, instrumental in creating ECC keys. These keys are regenerated with each system restart, significantly reducing the risk of key leakage.

Required compile time macros:

The following is required to secure the pre-master key. The Macro USE_DBGMON must not be set, and the code must be compiled with macro NO_LDEBUG set to disable the Lua debug API.

NetIo Details

The NetIo is typically used during development and is a requirement when developing code on an embedded device with no native file system support. The NetIo is a network file client and enables the device to fetch files from your host computer during development. You may use the Mako Server as the file server, but you must then configure a Mako Server Web File Server instance. See the NetIo Tutorial for details on using the client and server to set up a network file system.

Note that you may get severe performance degradation when using the NetIo since the NetIo generates multiple requests for each resource fetched. The NetIo speed is directly proportional to the speed of the TCP/IP stack being used in the embedded system. The faster the TCP/IP stack, the faster the NetIo will respond. The following diagram illustrates a page request using the NetIo:

Browser        Embedded System         Web File Server
  |                   |                       |
  |    get page       |                       |
  | --------------->  |                       |
  |                   |  stat (file exists?)  |
  |                   | --------------------> |
  |                   |         yes           |
  |                   | <-------------------  |
  |                   |                       |
  |                   |   get fragment 1      |
  |                   | --------------------> |
  |                   |    fragment 1         |
  |     response      | <-------------------  |
  | <---------------  |                       |
  |                   |                       |
  |                   |   get fragment 2      |
  |                   | --------------------> |
  |                   |    fragment 2         |
  |     response      | <-------------------  |
  | <---------------  |                       |
  |                   |                       |
  |                   |                       |

Figure 6: Browser to Device to WFS Sequence Diagram