#X.509 Certificates
#define FIO_X509
#include "fio-stl.h"This module parses DER-encoded X.509v3 certificates for TLS 1.3 style certificate checks. It is a compact parser, verifier, trust-store checker, TLS Certificate-message splitter, and small self-signed certificate generator.
It is non-allocating while parsing: fio_x509_cert_s stores pointers into the original DER bytes. Keep those bytes alive. Certificates dislike disappearing floors.
Scope note: this is a minimal TLS-oriented X.509 implementation, not a full PKI policy engine. Not all X.509 features are supported.
#Supported Pieces
- RSA, ECDSA P-256, ECDSA P-384, and Ed25519 public keys.
- RSA PKCS#1 v1.5, RSA-PSS, ECDSA, and Ed25519 signature verification.
- Validity period checks.
- Hostname matching using SAN DNS names and CN fallback, with one-label wildcards.
- Basic Constraints and Key Usage.
- Certificate chain validation against an optional trust store.
- TLS 1.3 Certificate message parsing.
- Self-signed certificate generation for Ed25519 and P-256 keys.
#Main Types
#Key and Signature Enums
typedef enum {
FIO_X509_KEY_UNKNOWN = 0,
FIO_X509_KEY_RSA = 1,
FIO_X509_KEY_ECDSA_P256 = 2,
FIO_X509_KEY_ECDSA_P384 = 3,
FIO_X509_KEY_ED25519 = 4,
} fio_x509_key_algo_e;typedef enum {
FIO_X509_SIGNATURE_UNKNOWN = 0,
FIO_X509_SIGNATURE_RSA_PKCS1_SHA256 = 1,
FIO_X509_SIGNATURE_RSA_PKCS1_SHA384 = 2,
FIO_X509_SIGNATURE_RSA_PKCS1_SHA512 = 3,
FIO_X509_SIGNATURE_RSA_PSS_SHA256 = 4,
FIO_X509_SIGNATURE_RSA_PSS_SHA384 = 5,
FIO_X509_SIGNATURE_RSA_PSS_SHA512 = 6,
FIO_X509_SIGNATURE_ECDSA_SHA256 = 7,
FIO_X509_SIGNATURE_ECDSA_SHA384 = 8,
FIO_X509_SIGNATURE_ED25519 = 9,
} fio_x509_signature_algo_e;#Key Usage and Errors
fio_x509_key_usage_e defines RFC 5280 key-usage bits such as FIO_X509_KU_DIGITAL_SIGNATURE, FIO_X509_KU_KEY_ENCIPHERMENT, and FIO_X509_KU_KEY_CERT_SIGN. ASN.1 bit strings use MSB-first ordering, so the constants look a little backwards until they save you from off-by-one sadness.
fio_x509_error_e gives chain validation results: FIO_X509_OK, parse failure, expired/not-yet-valid, signature failure, issuer mismatch, not-a-CA, no trust anchor, hostname mismatch, empty chain, and chain-too-long.
#fio_x509_trust_store_s
typedef struct {
const uint8_t **roots;
const size_t *root_lens;
size_t root_count;
} fio_x509_trust_store_s;A simple root store: arrays of DER certificate pointers and lengths.
#fio_tls_cert_entry_s
typedef struct {
const uint8_t *cert;
size_t cert_len;
} fio_tls_cert_entry_s;One certificate entry extracted from a TLS 1.3 Certificate handshake message.
#fio_x509_cert_s
typedef struct fio_x509_cert_s fio_x509_cert_s;The parsed certificate structure uses non-owning buffer views
(fio_buf_info_s / fio_ubuf_info_s) and packs to 256 bytes with no
interior padding:
verified: non-zero when a TLS backend verified this certificate's chain (peer inspection only; always zero afterfio_x509_parse);der: a reference to the original DER bytes (not a copy);fingerprint: 32-byte SHA-256 of the DER bytes (seefio_x509_fingerprint);version,serial, and validity timestamps;- raw subject and issuer DNs;
- subject CN;
- public key type and key data;
- signature algorithm and signature bytes;
- TBS certificate bytes used for verification;
- Basic Constraints (
is_ca), Key Usage (has_key_usage,key_usage), and SAN data (first DNS name, first IP address, and the raw SAN extension for iterating the rest).
All view pointers reference the original DER buffer.
#Parsing and Single-Certificate Checks
#fio_x509_parse
SFUNC int fio_x509_parse(fio_x509_cert_s *cert,
const uint8_t *der_data,
size_t der_len);Parses one DER certificate. cert is zeroed first. Returns 0 on success, -1 on parse error.
#fio_x509_fingerprint
SFUNC void fio_x509_fingerprint(fio_x509_cert_s *cert);Computes the SHA-256 of the certificate's DER bytes into
cert->fingerprint (32 raw bytes). Call after fio_x509_parse; hashing is
lazy so parsing never pays for it. Requires the SHA2 module.
#fio_x509_verify_signature
SFUNC int fio_x509_verify_signature(const fio_x509_cert_s *cert,
const fio_x509_cert_s *issuer);Verifies that issuer signed cert, using the issuer public key and the certificate signature algorithm. Returns 0 when the signature is valid, -1 otherwise.
#fio_x509_check_validity
FIO_IFUNC int fio_x509_check_validity(const fio_x509_cert_s *cert,
int64_t current_time);Checks not_before <= current_time <= not_after. Returns 0 when the certificate is in its validity window.
#fio_x509_match_hostname
SFUNC int fio_x509_match_hostname(const fio_x509_cert_s *cert,
const char *hostname,
size_t hostname_len);Checks whether a certificate matches a hostname. SAN DNS entries are supported, with CN fallback. Wildcards are one-label wildcards such as *.example.com; they do not swallow a.b.example.com.
Returns 0 for a match, -1 for no match.
Distinguished Names are compared as raw DER with the core
FIO_BUF_INFO_IS_EQ macro (e.g.,
FIO_BUF_INFO_IS_EQ(cert.issuer, root.subject)).
#Chain Validation
#fio_x509_verify_chain
SFUNC int fio_x509_verify_chain(const uint8_t **certs,
const size_t *cert_lens,
size_t cert_count,
const char *hostname,
int64_t current_time,
fio_x509_trust_store_s *trust_store);Validates a certificate chain for TLS-style use.
Expected order:
certs[0]: end-entity / server certificate.certs[1]: intermediate that signedcerts[0].certs[n-1]: closest-to-root certificate.
Validation parses all certificates, checks validity periods, optionally matches the hostname, verifies each signature with the next certificate, checks issuer/subject DN links, requires CA certificates where needed, and optionally checks the final certificate against trust_store.
Trust anchors are matched by (subject DN, public key): the anchor's key must verify the final certificate's signature. This also covers self-signed certificates — a same-named impostor with a different key is rejected.
Returns FIO_X509_OK (0) on success, or a FIO_X509_ERR_* code.
#fio_x509_is_trusted
SFUNC int fio_x509_is_trusted(const fio_x509_cert_s *cert,
fio_x509_trust_store_s *trust_store);Checks whether cert appears in the trust store by subject DN match. Returns 0 if trusted, -1 if not found.
#fio_x509_error_str
FIO_IFUNC const char *fio_x509_error_str(int error);Returns a static string for a chain validation error code.
#TLS Certificate Messages
#define FIO_TLS_CERT_PARSE_ERROR ((size_t)-1)#fio_tls_parse_certificate_message
SFUNC size_t fio_tls_parse_certificate_message(fio_tls_cert_entry_s *entries,
size_t max_entries,
const uint8_t *data,
size_t data_len);Parses a TLS 1.3 Certificate message body, after the handshake header. It extracts certificate entries and skips per-certificate extensions.
Returns the number of certificates parsed, or FIO_TLS_CERT_PARSE_ERROR on malformed input.
#Self-Signed Certificate Generation
Generation supports Ed25519 and P-256 key pairs.
typedef enum {
FIO_X509_KEYPAIR_ED25519 = 1,
FIO_X509_KEYPAIR_P256 = 2,
} fio_x509_keypair_type_e;fio_x509_keypair_s stores the selected key type, secret key bytes, public key bytes, and their lengths. Use fio_x509_keypair_clear when done.
fio_x509_cert_options_s controls the subject CN, organization, organizational unit, country, validity window, SAN DNS names, CA flag, and key-usage bits.
#fio_x509_keypair_ed25519
SFUNC int fio_x509_keypair_ed25519(fio_x509_keypair_s *keypair);Generates an Ed25519 key pair for certificate signing. Requires the Ed25519 module to be included. Returns 0 on success.
#fio_x509_keypair_p256
SFUNC int fio_x509_keypair_p256(fio_x509_keypair_s *keypair);Generates a P-256 key pair for certificate signing. Requires the P-256 module to be included. Returns 0 on success.
#fio_x509_self_signed_cert
SFUNC size_t fio_x509_self_signed_cert(uint8_t *buf,
size_t buf_len,
const fio_x509_keypair_s *keypair,
const fio_x509_cert_options_s *options);Writes a DER-encoded self-signed X.509v3 certificate. Call with buf == NULL to get a worst-case buffer size, then call again with a real buffer.
Returns bytes written, or 0 on error.
#fio_x509_keypair_clear
FIO_IFUNC void fio_x509_keypair_clear(fio_x509_keypair_s *keypair);Securely clears key material and zeros the structure.
#Example: Parse and Check Hostname
#define FIO_X509
#include "fio-stl.h"
int check_cert(const uint8_t *der, size_t der_len, int64_t now) {
fio_x509_cert_s cert;
if (fio_x509_parse(&cert, der, der_len))
return -1;
if (fio_x509_check_validity(&cert, now))
return -1;
if (fio_x509_match_hostname(&cert, "example.com", 11))
return -1;
return 0;
}#Practical Notes
- Define the crypto modules you need before including the STL: RSA, P-256, P-384, Ed25519, SHA-2, and ASN.1 may all matter depending on certificate algorithms.
trust_store == NULLskips root trust checking infio_x509_verify_chain; useful for structural tests, not for real trust decisions.- Hostname checks are DNS-name focused. IP address SAN handling is not a full replacement for platform certificate validation.
- Parsed strings and DNs are raw certificate data. Normalize policy elsewhere if your application needs browser-grade PKI behavior.