Native
Link a static library into your binary. It holds no key, opens no socket to Root Herald, and writes into buffers you own.
#include <rootherald.h>
/* challenge: the "rhc1.…" string your backend relayed, verbatim. Returns malloc'd JSON or NULL. */
char* answer_challenge(const char* challenge) {
RH_HANDLE h = NULL;
if (RootHeraldOpen(&h) != RH_OK) return NULL; /* no TPM reachable */
size_t cap = 64 * 1024, len = 0; /* generous first size; grow once if told to */
char* evidence = malloc(cap);
RH_STATUS st = RootHeraldRespond(h, challenge, NULL, evidence, cap, &len, NULL, 0, NULL);
if (st == RH_ERR_BUFFER_TOO_SMALL) {
evidence = realloc(evidence, len); cap = len;
st = RootHeraldRespond(h, challenge, NULL, evidence, cap, &len, NULL, 0, NULL);
}
if (st == RH_ERR_NOT_ENROLLED) { /* first run: EnrollBegin + EnrollComplete, elevated on Windows, then retry */ }
RootHeraldClose(h);
if (st != RH_OK) { free(evidence); return NULL; }
return evidence; /* POST { challengeId, evidence } to your backend */
}Install
One archive per platform from the sdk-windows, sdk-linux and sdk-macos releases: lib/, include/rootherald.h, SHA256SUMS.
link.exe app.obj RootHerald.lib ncrypt.lib tbs.lib winhttp.lib bcrypt.lib crypt32.lib # Windows
gcc app.o -lrootherald -ltss2-esys -ltss2-tctildr -ltss2-mu -lcurl -lpthread # Linux
clang app.o -lrootherald -framework Security -framework Foundation # macOSFirst contact
RH_ERR_NOT_ENROLLED means run the two enroll legs once on one session — RootHeraldEnrollBegin, relay through your backend, RootHeraldEnrollComplete, relay again. On Windows that session must be elevated; the SDK returns RH_ERR_ELEVATION_REQUIRED and never elevates for you. Code and patterns on the Enrollment and Windows elevation pages.
The server half
Identical for every client and written out once in the quickstart: send { challengeId, evidence } over whatever channel your app already has to your backend, which calls rh.verify().
Windows is the complete desktop path today. The Linux (tpm2-tss) and macOS (Secure Enclave) collectors share the byte-identical header; check RootHeraldPreCheck for what the machine can serve before minting an ask it cannot answer.