This example gives a C web server its own HTTPS certificate and renews it automatically. It uses the Barracuda Web Server (BWS), SharkSSL, and the SharkTrustX (default) or the SharkCA portal to obtain a test certificate from Let's Encrypt. A small web page shows whether the certificate is ready, when it expires, and when renewal is due. No Lua runtime is required.
Do not use this C module if you are using Lua. Instead, use the Lua ACME plugin.
Use this guide to build and run the example on Windows or Linux, then use the same void barracuda(void) entry point with your target port, as in the other BAS examples. For certificate concepts and the C integration contract, read the SharkTrustX C user manual.
The default build uses staging certificates. It exercises real enrollment and certificate issuance, but its issued certificates are for testing and produce browser trust warnings. The device still validates the HTTPS services it connects to. See Let's Encrypt's staging documentation. After starting, browsing to the example, and accepting the warning, you may click the certificate and its chain in the browser, download the Let's Encrypt root CA staging certificate, and install it in your certificate store. The next time you start the browser, it will trust the connection.
amalgamation/BWS.c, which includes xrc/misc/SharkTrustX.c, using the headers and SharkSSL sources in that tree. It does not need a prebuilt BAS library or a resource compiler.src/tokengen.c supplies credentials for x.realtimelogic.com. You can use these credentials to try the example. To use your own credentials, download tokengen.c from your SharkTrustX or SharkCA portal, replace the included file, and rebuild. For SharkCA, follow Switch to SharkCA; replacing credentials alone does not select the private-CA protocol.src/start.h, replace John Doe's placeholder email, john.doe@example.com, with your own contact email before building. SharkCA does not use a contact email. Set the preferred name to a label such as controller-17; the portal chooses the final full DNS name.8080 and 8443. A certificate authority (CA) is the service that signs the certificate.When using your own portal credentials, keep tokengen.c and the resulting executable or firmware private. If you change credentials after running the example, use a separate state directory for the new enrollment.
This same example can use SharkCA to obtain private certificates for devices on your network. There is no permanent public SharkCA test portal. Set up your own portal, for example with Mako Server on your computer, using the SharkCA installation guide.
443. If the portal runs on another computer, localhost refers to the device itself.src/tokengen.c.src/start.c loads ISRG Root X1 into clientSsl with SharkSsl_setCAListEx(). If your portal's HTTPS certificate uses another issuer or a local CA, replace that list with a SharkSSL-format CA list containing the appropriate trusted CA. The portal certificate must cover its hostname. Keep certificate validation enabled.SHARKTRUSTX_PRIVATE_CA to 1 as described below, and rebuild. The supplied builds then define the C macro for the example and BWS and include the BAS C mDNS responder. Replacing credentials alone does not select the private protocol.EXAMPLE_STATE_DIR to an existing, empty directory for the SharkCA enrollment. Keep your public-profile state separate and retain the new directory for restarts. Set EXAMPLE_NAME to a preferred label without .local; the portal assigns the final name.Both build paths default to SHARKTRUSTX_PRIVATE_CA=0, which leaves the C macro undefined and uses SharkTrustX with Let's Encrypt staging. For Visual Studio, change the value in the UserMacros section of VcMake/example.vcxproj from 0 to 1, then select Rebuild. Alternatively, run this command from a Visual Studio developer command prompt at the BAS root:
rem Use your SharkCA tokengen.c and a separate state directory before running. msbuild examples\SharkTrustX\VcMake\example.vcxproj /t:Rebuild ^ /p:Configuration=Debug /p:Platform=x64 ^ /p:SHARKTRUSTX_PRIVATE_CA=1
For GNU Make, set SHARKTRUSTX_PRIVATE_CA=1 in make/Makefile or pass it with every build command. Clean with the old settings before changing profiles. From examples/SharkTrustX/make on Linux:
# Remove public-profile objects, preserving saved state. make plat=posix build=debug clean # Build the private profile; src/tokengen.c must belong to your SharkCA portal. make plat=posix build=debug SHARKTRUSTX_PRIVATE_CA=1 exe
On Windows, use the same setting with plat=win ARC=x64 from the compiler prompt described below. The executable retains the filename SharkTrustX-staging; its startup trace and status page identify the selected CA profile. To return to SharkTrustX, clean using the private build settings, restore the public portal credentials and state directory, set the build setting back to 0, and rebuild. In a custom SDK project, define the C macro consistently for all sources when using SharkCA; leave it undefined for the public profile.
The private profile derives its CA directory as https://portal-domain/acme/directory. It omits the public profile's contact email, Let's Encrypt staging directory, and terms setting. No changes to these assignments in start.c are needed when switching profiles.
After portal confirmation, the example advertises the assigned .local name through the BAS C mDNS responder. Multicast DNS (mDNS) lets computers on the same local network resolve the name without a DNS server. The browser computer must support mDNS, and the network/firewall must permit multicast traffic on UDP port 5353. Use the HTTPS link on the status page after the certificate is ready.
The responder selects the first usable active multicast LAN interface, publishes its IPv4 address and, when available with USE_IPV6, its IPv6 address, and follows address changes. On a computer with multiple adapters, the selected interface can be a virtual adapter. Look for mDNS advertising in the trace. If initial setup fails, correct the network/port problem and restart. mDNS normally stays on the local link; it does not provide name resolution across routers or make private certificates trusted. The example uses the portal-assigned name without local conflict detection or renaming.
Open VcMake/example.sln using Visual Studio and build. The application is compiled as C.
Alternatively, run the supplied wrapper from a standard CMD console at the BAS root:
rem Build with assertions and start from the output directory. examples\SharkTrustX\VcMake\build.cmd Debug x64 cd examples\SharkTrustX\obj\debug SharkTrustX-staging.exe
The wrapper discovers Visual Studio and invokes MSBuild. With no arguments it selects Release x64. Use Release for optimization or Win32 for a 32-bit executable. Like the other examples, both the executable and intermediate files go in obj/debug/ or obj/release/. Use Visual Studio's Rebuild command when switching between Win32 and x64.
Keep the console open and continue with Check enrollment and HTTPS. The console reports the private state path and any startup error.
Install GCC, GNU Make, and the zlib development package required by the shared POSIX target. Run from the BAS root:
# Build and start from the output directory. cd examples/SharkTrustX/make make plat=posix build=debug exe cd ../obj/debug ./SharkTrustX-staging
The example saves its certificate, private keys, and portal enrollment through a DiskIo instance created in barracuda(). Its root is EXAMPLE_STATE_DIR in src/start.h. The default, ".", stores files directly in the working directory selected by the shared startup; the example does not create a state subdirectory.
With the Debug run commands above, or when starting Debug from Visual Studio, the files are stored here. Replace BAS with your BAS installation directory:
| System | State directory | Example state file |
|---|---|---|
| Windows | BAS\examples\SharkTrustX\obj\debug | BAS\examples\SharkTrustX\obj\debug\sharktrustx.0 |
| Linux | BAS/examples/SharkTrustX/obj/debug | BAS/examples/SharkTrustX/obj/debug/sharktrustx.0 |
For a Release build, start from obj/release instead. Visual Studio sets the working directory to the selected output directory. If you start from another directory, the shared Main.c may change the working directory while locating the example's obj directory. The console reports that change and the configured state path. The shared trace handler also writes HttpTrace.txt in the working directory.
The client writes the following files directly in that directory, without creating another subdirectory:
| Filename | Contents |
|---|---|
sharktrustx.0, sharktrustx.1 | Alternating binary records containing the certificate, private keys, and enrollment data. You may see only one of these files after a successful update. |
sharktrustx.reset | A marker used to complete an interrupted cleanup. It is normally absent. |
Keep this directory for normal restarts, and run only one instance of the example against it. The saved private keys and credentials are unencrypted. Keep the directory private and never serve it over HTTP.
Set EXAMPLE_STATE_DIR to an existing, writable directory and rebuild. Use forward slashes in the C string, including on Windows. For example, set it to "C:/Users/John/SharkTrustX-state" on Windows, "/home/john/sharktrustx-state" on Linux, or the appropriate persistent-storage path for your device. The example has no command-line options.
A new empty directory creates a separate portal enrollment. Reuse saved state with the same portal credentials, preferred name, and CA settings. To keep an enrollment from the previous example version, set this path to its existing state directory. The makefile's clean target preserves state files.
Open http://localhost:8080/ on the machine running the example. From another computer, substitute the device's reachable IP address. This HTTP page works before a certificate exists and refreshes every ten seconds.
Wait for portal enrollment. The page and console show the confirmed DNS name. Use that name, even if it differs from your preferred label. Confirmation means the portal has enrolled the device; certificate issuance may still be running.
Look for Installed; HTTPS is ready, with expiry and renewal dates. The page then shows an Open this page over HTTPS link using the assigned name on port 8443. No HTTPS listener is opened until a usable certificate is installed.
Follow that link to inspect the HTTPS connection. In the default profile, a staging certificate causes a trust warning even with the correct name. With SharkCA, import your zone's root CA and use the assigned .local name from the same LAN. Typing https://localhost:8443/ or a raw IP also uses a name that the public-profile certificate does not cover.
Press Ctrl+C in the host console to exit. Restart with the same credentials, settings, and state directory. A saved usable certificate is restored, then enrollment and automatic renewal continue.
A newly confirmed name is not a certificate-ready signal. After a restart, the saved certificate may be ready before the portal confirms the name again.
| Field | What it tells you |
|---|---|
| Certificate | Whether the managed HTTPS listener currently has an unexpired certificate. Initial enrollment can be active while this still says it is waiting. |
| Confirmed DNS name | The portal-assigned name to use in the browser. It is reported independently of certificate readiness. In the SharkCA profile, confirmation starts mDNS for this name. |
| Expires | The installed certificate's expiry date, in UTC (GMT). |
| Renewal due | The midpoint of the installed certificate's validity period. This can be in the past while issuance or retries are running; it is not the next retry time. |
| Last notification | The last certificate-ready or error notification. An error can coexist with a still-valid certificate. The accompanying retry event is logged to the console without hiding the error on the page. |
The public profile proves control of the name using a temporary DNS TXT record managed by the portal. The CA reads DNS; it does not need to connect to the example's HTTP or HTTPS port. Your browser still needs to resolve the assigned name and reach the device. Certificate issuance does not set up router forwarding or a remote-access tunnel.
With USE_IPV6 enabled, both HTTP and HTTPS try IPv6 first, then IPv4 on their respective ports. Successful sockets are retained. Windows normally opens two sockets per service; Linux normally opens one dual-stack IPv6 socket per service that also accepts IPv4. Platform settings can change this. Both HTTPS listeners share one certificate and TLS context. Without USE_IPV6, only IPv4 is attempted.
The console identifies the HTTP sockets that opened. HTTPS is ready means at least one HTTPS listener has an unexpired certificate.
Edit src/start.h or supply compiler definitions before building. The example uses these settings:
| Setting | C type | Default | Meaning |
|---|---|---|---|
EXAMPLE_NAME | String literal | sharktrustx-c | Preferred label, 1 to 63 ASCII letters, digits, or hyphens; no leading/trailing hyphen or dot. Keep it stable when reusing state. |
EXAMPLE_EMAIL | String literal | john.doe@example.com | John Doe's placeholder for the public ACME account contact. Replace it before public-profile enrollment; unused with SharkCA. |
EXAMPLE_STATE_DIR | String literal | "." | Existing writable directory used as the private DiskIo root. Select persistent storage on a device. |
EXAMPLE_HTTP_PORT | Integer constant | 8080 | Unused port from 1 to 65535 for the status page. |
EXAMPLE_HTTPS_PORT | Integer constant | 8443 | A different unused port from 1 to 65535, managed by SharkTrustX. |
By default, the configuration in src/start.c selects Let's Encrypt's staging service, accepts its terms, and loads the ISRG Root X1 certificate used to verify outbound HTTPS. Review the CA's terms before running the example. For the private-CA variant and its setup, see Switch to SharkCA.
| File | Role in the example |
|---|---|
examples/misc/standalone/Main.c | Shared entry point for systems using main(). Calls hostInit(), then barracuda(). |
examples/misc/standalone/HostInit.c | Shared host setup for networking, trace output, and fatal-error handling. |
src/start.h | Defines the contact email, preferred name, ports, and state directory. Includes the shared startup declarations. |
src/start.c | Implements void barracuda(void): initializes randomness, persistent storage, and the server; opens HTTP; starts certificate management; and, with SharkCA, advertises the confirmed name through mDNS. |
src/InstallVD.c | Provides the status page and logs certificate events. It reads the current certificate state using SharkTrustX_getStatus(). |
src/tokengen.c | Supplies the portal address and authentication credentials used to enroll the device. |
xrc/misc/SharkTrustX.c | Handles enrollment, certificate requests, storage, renewal, and the HTTPS listeners. BWS includes this library code. |
Enrollment and renewal run on a timer worker while the server continues handling requests. With SHARKTRUSTX_PRIVATE_CA, mDNS has its own timer sharing the dispatcher mutex, so blocking certificate requests do not delay scheduled name replies. A changed name closes the old responder before advertising the new one; IP-only enrollment stops advertisement. Replacing a certificate closes existing HTTPS connections, so browsers reconnect. The HTTP status page remains available.
The makefile compiles BWS with SHARKTRUSTX and BA_JSON=1, including SharkTrustX and its native HTTP client, timer, and certificate signing request support. It also sets SHARKSSL_ENABLE_CERTINFO_PARSE_API=1 to enable SharkSSL's public certificate-info parser. Do not compile SharkTrustX.c separately. It does not compile Lua or BAS.c. In an existing application, use the same integration pattern without starting a second dispatcher or duplicating the BWS runtime.
make/Makefile uses the shared builds/generic/examples.mk, rules.mk, and platform Target.mk files, like the other BAS examples. Use build=release for optimization; release is the default. The targets are exe (default), lib, and clean. Cleaning with the same platform/build variables removes build outputs, preserving private state.
On Windows, use a Visual Studio x64 Native Tools Command Prompt with GNU Make and the sh, mkdir, and rm utilities on PATH. The BAS bin/make.exe and Cygwin shell utilities can be used. From the BAS root:
rem Use a compiler prompt matching ARC; the makefile does not switch compilers. cd examples\SharkTrustX\make ..\..\..\bin\make.exe plat=win ARC=x64 build=debug exe cd ..\obj\debug SharkTrustX-staging.exe
Makefile outputs use obj/debug/ or obj/release/, matching the other examples and the Visual Studio project. ARC selects the shared Windows target's architecture setting; keep it consistent with the compiler tools prompt. Run clean with the current build settings before changing platform, compiler, architecture, or feature definitions. Use a clean rebuild when switching between the makefile and Visual Studio. You can override ODIR to keep builds for multiple targets.
The Windows BWS port enables USE_IPV6. For Linux, enable it in every compilation unit through the shared makefile setting. Clean the previous build before changing this setting:
# Run from examples/SharkTrustX/make; rebuild with IPv6 enabled. make plat=posix build=debug clean make plat=posix build=debug USE_IPV6=1 exe
An IPv6 build must use a BWS network port that implements IPv6. For example, the existing FreeRTOS/lwIP netconn port supports IPv4 only; USE_IPV6 alone does not add IPv6 support to that port. An unsuccessful IPv6 attempt falls back to IPv4, following the same listener sequence.
The server uses the standard void barracuda(void) entry point. It can use any BAS target port that supplies the required thread, network, clock, and persistent-storage services. FreeRTOS, Zephyr, INTEGRITY, and VxWorks below are examples of port selection, not a fixed list of supported operating systems.
Call barracuda() once from the application's usual server task after initializing the scheduler, heap, console, networking/DNS, UTC clock, and persistent storage. As with the other BAS examples, it runs the dispatcher in that task. Use the shared Main.c and HostInit.c on systems with main(); an RTOS application supplies its normal board startup, trace callback, and fatal-error handler.
Compile src/start.c, src/InstallVD.c, src/tokengen.c, and amalgamation/BWS.c with the feature definitions described above. Use your target's existing BAS headers and thread, socket, and filesystem implementations. BWS already includes some port sources; add each implementation only once. If BWS has no branch for your port, define NO_DEFAULT_BUILD and compile the target's existing thread, dispatcher, and DiskIo implementations separately.
| Example target | Port setup in the target build |
|---|---|
| FreeRTOS with lwIP | BA_FREERTOS selects BWS's FreeRTOS/lwIP sources. Select matching headers and define BA_LWIP, USE_DLMALLOC, and NO_MALLINFO=1 consistently across the build. Initialize the allocator and add the filesystem port used by the board. |
| Zephyr | Use BA_ZEPHYR and NO_DEFAULT_BUILD, the Zephyr headers and ThreadLib.c, the generic BSD SoDisp.c, and a DiskIo implementation for the mounted filesystem. |
| INTEGRITY | Define BA_INTEGRITY in the build and select the INTEGRITY and BSD socket headers. BWS includes the INTEGRITY thread and generic BSD dispatcher sources; add the chosen filesystem port. |
| VxWorks | Define BA_VXWORKS in the build and select the VxWorks headers. BWS includes the VxWorks thread and generic BSD dispatcher sources; add the chosen filesystem port. |
Use your SDK project or the usual makefile tinc setting to select a target file. The example makefile's lib target omits shared host startup so your application can provide it. This command is a template; replace the target-file path with your compiler and SDK settings:
# Build the server library for the application's normal startup. make tinc=/path/to/Target.mk lib
The target file supplies the compiler, ABI settings, BAS port definitions, include directories, and archive tools, following the shared BAS makefile conventions. It may also set PORTSRC to a space-separated list of additional C source paths that BWS does not include.
For SharkCA, compile xrc/misc/BamDNS.c and one mDNS socket/discovery port in addition to the sources above. The supplied Windows/Linux builds select src/arch/bsdSocket/BamDNS-Sock.c automatically with SHARKTRUSTX_PRIVATE_CA=1. Windows also links iphlpapi.lib. Keep BAS_LOADED undefined to exclude Lua bindings, and enable USE_DGRAM in the selected BAS socket port.
The application uses the public BamDNS C APIs without OS-specific calls. The optional make variable MDNSSRC is a space-separated list of C source paths for a replacement socket/discovery implementation; it defaults to the supplied BSD port. Automatic interface selection uses BamDNS_getNetInfo(). See the BamDNS integration guide for its port contract.
A BAS TCP port alone does not guarantee mDNS support. The target stack must supply multicast sockets, interface discovery, and packet metadata. For example, the FreeRTOS/lwIP netconn port cannot use the BSD adapter unchanged. Supply a matching adapter, or adapt the confirmed-name callback to the stack's existing mDNS responder. The public SharkTrustX build does not require mDNS.
Set EXAMPLE_STATE_DIR to an existing directory on the device's persistent filesystem. The example constructs a static DiskIo instance and passes it to SharkTrustX as an IoIntf. If your application uses another persistent IoIntf implementation, replace that storage setup and assign the instance to config.io; keep it alive for the lifetime of the server. The state files go directly in its root, which is never exposed over HTTP.
Supply real entropy before using TLS on a device. The platform section at the top of
start.cseeds SharkSSL from the operating system on Windows and Linux. For other targets,seedRandom()contains a predictable function-address placeholder. Replace it withsharkssl_entropy()calls using the board's hardware random generator or another secure entropy source.
| Symptom | What to check |
|---|---|
| Cannot open the status page | Read startup output. Check that the process is still running, port 8080 is free, and the browser can reach the machine. A remote browser also needs firewall access. |
Trust error -6 | Check the device's UTC clock, outbound CA anchors, and portal/service certificate. This error concerns the device's outbound HTTPS, independently of the browser's staging warning. |
Identity error -2 | Check whether the build changed tokengen source, preferred label, profile, or CA directory while retaining old state. Restore the original settings or use the documented cleanup lifecycle. |
Storage error -3 | Check EXAMPLE_STATE_DIR, permissions, capacity, and the selected filesystem port. The directory must already exist. Do not delete files merely to hide an error. |
Portal error -4 or CA error -5 | Check DNS/outbound connectivity, portal credentials, and CA availability. The worker logs a retry notification and stays active. |
Key or listener error -7 | Check available memory, entropy initialization, required SharkSSL features, and whether another server owns port 8443. |
| Name shown but no HTTPS link yet | Enrollment has confirmed the name; wait for certificate installation and inspect subsequent console events. |
| SharkCA .local name does not resolve | Check the mDNS startup trace, selected LAN adapter, browser OS mDNS support, and multicast/firewall access to UDP 5353. Use the same local network. |
| HTTPS ready but browser cannot connect | Check name resolution and the route/firewall to port 8443. Use the assigned name. Issuance does not create remote access. |
| HTTPS connects but the browser warns | A staging trust warning is expected in the public profile. With SharkCA, install the zone's root CA in the browser and use the confirmed name. A URL using localhost or a raw IP adds a name mismatch. See the manual's public/private trust explanation before changing trust settings. |
| Renewal due is in the past | It is the certificate lifetime midpoint, not a completion promise. Check current readiness, expiry, and the preceding error; retries may still be running. |
For all callback values and recovery contracts, see the manual's error reference. Return to the BAS examples index or shared build introduction for the surrounding example structure.