At Riptides, we’ve been building a solution that securely federates workloads with Oracle Cloud Infrastructure (OCI) — as well as with AWS, GCP, and Azure. During this process, we faced a technical challenge that led us to create — and now open source — oci-req-signer-c, a minimal C implementation of the OCI request signing algorithm. This is part of our broader effort to enable deep, kernel-level identity federation across all major cloud providers, a topic we explored in detail in our post, Why Cloud-Native Federation Isn’t Enough for Non-Human Identities in AWS, GCP, and Azure.
In our architecture, workloads obtain temporary OCI credentials (User Principal Session Tokens) by exchanging ID tokens issued by the Riptides Control Plane. These credentials are then injected into OCI API requests on the fly entirely transparently to the workloads themselves.
Here’s the key technical detail:
Each OCI API request must include a valid Authorization header signed with the RSA private key associated with the temporary credential.
In our system:
All of this happens in kernel space, inside a Linux kernel module responsible for intercepting and modifying outgoing HTTP(S) traffic.
You can also read more about our kernel-based architecture and how we integrate SPIFFE and kTLS in Seamless Kernel-Based Non-Human Identity with kTLS and SPIFFE
While OCI provides official SDKs for Python, Java, Go, and others, none of them include a C implementation of the signing algorithm. Moreover we couldn’t find one which is suitable for use in kernel modules or other low-level environments.
We needed a pure C implementation, with no dynamic allocations and no dependency on libc features unavailable in the kernel. When we couldn’t find one, we decided to build it.
We encountered similar challenges with AWS request signing, which led us to develop and open source libsigv4 — a portable C library implementing AWS SigV4 with kernel compatibility.
oci-req-signer-c is a lightweight, dependency-minimal C library for computing OCI-style HTTP request signatures.
It’s designed to work both in user space and kernel space, or anywhere a small, efficient, and auditable signer is required.
.a or .soOCI_SYSTEM_HEADER)#include "oci_signer.h"
// Example-specific buffer size constants
#define EXAMPLE_AUTH_HEADER_MAX_LEN 4096
int main()
{
// Sample request parameters
const char *method = "GET";
const char *uri = "/20160918/instances";
const char *host = "iaas.us-phoenix-1.oraclecloud.com";
const char *date = "Thu, 05 Jan 2014 21:31:40 GMT";
const char *payload = "";
// Example key_id in format: tenancy/user/fingerprint
const char *key_id =
"ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f15p2b2m2yt2j6rx32uzr4h25vqstifsfdsq/"
"ocid1.user.oc1..aaaaaaaat5nvwcna5j6aqzjcaty5eqbb6qt2jvpkanghtgdaqedqw3rynjq/"
"20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34";
// Alternative: Example key_id using session token format
// const char *key_id = "ST$aaaaaaaa7tz3aaaaaaaaaymq2maaaaaaabfwiljtdnfgqaaaa";
// Initialize OCI signer parameters
oci_signer_params_t signer_params = {0}; // Zero-initialize the structure
// Set the private key in DER format using the binary type
signer_params.private_key.data = ...;
signer_params.private_key.len = ...;
signer_params.key_id = oci_signer_string((unsigned char *)key_id);
signer_params.method = oci_signer_string((unsigned char *)method);
signer_params.uri = oci_signer_string((unsigned char *)uri);
signer_params.payload = oci_signer_string((unsigned char *)payload);
signer_params.headers[0].key = oci_signer_string((unsigned char *)"host");
signer_params.headers[0].value = oci_signer_string((unsigned char *)host);
signer_params.headers[1].key = oci_signer_string((unsigned char *)"date");
signer_params.headers[1].value = oci_signer_string((unsigned char *)date);
signer_params.num_headers = 2;
// Set the required crypto functions
signer_params.sha256 = ...;
signer_params.rsa_sign_sha256 = ...;
signer_params.base64_encode = ...;
// Buffer for the Authorization header
unsigned char *auth_header_buf = malloc(EXAMPLE_AUTH_HEADER_MAX_LEN);
memset(auth_header_buf, 0, EXAMPLE_AUTH_HEADER_MAX_LEN);
oci_signer_header_t auth_header =
{
.value = {.data = auth_header_buf}
};
int status = oci_signer_sign(&signer_params, &auth_header, EXAMPLE_AUTH_HEADER_MAX_LEN);
if (status == OCI_SIGNER_OK)
{
printf("Authorization header value: %.*s\n", auth_header.value.len, auth_header.value.data);
}
else
{
fprintf(stderr, "Failed to sign the request\n");
}
free(auth_header_buf);
free(key_data);
}
This library powers our kernel-space credential injection system, enabling OCI authentication without any user-space process or SDK.
Our kernel module:
This enables transparent, secure, and short-lived identity federation for workloads accessing OCI resources.
We realized this signing challenge isn’t unique to us.
Anyone building low-level OCI integrations, embedded systems, or custom networking stacks might need a C implementation of OCI’s signing logic.
By open sourcing oci-req-signer-c, we aim to:
You can check out the source here: 👉 https://github.com/riptideslabs/oci-req-signer-c
We’d love feedback, especially from embedded developers running into the same challenges.
What started as an internal engineering need to make OCI request signing possible inside a Linux kernel module has evolved into a reusable, open-source library for the broader community.
We’re excited to share oci-req-signer-c and look forward to seeing how others use it in their projects.