-
-
Notifications
You must be signed in to change notification settings - Fork 5
Cryptography and TLS
NyxOS speaks TLS 1.2 to real HTTPS servers, using cryptographic primitives written from scratch in the kernel. It performs an ECDHE key agreement, encrypts with AES-128-GCM, verifies the server's ServerKeyExchange signature, and validates the certificate chain to a pinned trust anchor — with hostname and validity-date checks.
Every primitive here has a known-answer self-test runnable from the shell, checked against the published vectors for that algorithm.
Do not trust this with anything real. These implementations have never been reviewed by anyone outside the project, no constant-time behaviour is claimed, and the trust store holds five anchors rather than a real root set. See Security.
See also: Networking Stack, Selene Browser, Security, Shell
| Area | File | Provides | Self-test |
|---|---|---|---|
| Hashing | sha256.c |
SHA-256, HMAC-SHA256, PBKDF2 | — |
| Hashing | sha512.c |
SHA-512, SHA-384 (FIPS 180-4) | sha512test |
| AEAD | aes_gcm.c |
AES-128-GCM seal/open | gcmtest |
| ECDH | curve25519.c |
X25519 (RFC 7748) | x25519test |
| ECC | p256.c |
secp256r1 arithmetic, ECDSA-P256 verify | p256test |
| ECC | p384.c |
secp384r1 arithmetic, ECDSA-P384/SHA-384 verify | p384test |
| RSA | rsa.c |
PKCS#1 v1.5 and PSS signature verification | rsatest |
| RNG | csprng.c |
HMAC_DRBG-SHA256 (NIST SP 800-90A) | csprngtest |
| ASN.1 | der.c |
DER reader | dertest |
| PKI | x509.c |
Certificate-chain verification, SAN and date checks | chaintest |
| KDF | tls_prf.c |
TLS 1.2 PRF, P_SHA256
|
prftest |
| Protocol | tls.c |
Handshake, key schedule, record layer |
tlskeytest, tlsrectest, skp384test
|
csprng_bytes(out, n) is an HMAC_DRBG-SHA256, instantiated on first use from the best available hardware entropy — RDSEED/RDRAND, plus RDTSC jitter and the tick counter — and periodically reseeded. The TLS ClientHello random and every ephemeral key come from it.
This is a different thing from /dev/random, which is a plain xorshift64 PRNG suitable for scripts and nothing else. See Filesystem.
aes128_gcm_encrypt(key, iv12, aad, aad_len, pt, pt_len, ct, tag16);
int ok = aes128_gcm_decrypt(key, iv12, aad, aad_len, ct, ct_len, tag, pt);decrypt verifies the tag first and only writes the plaintext if it is valid — on failure the output buffer is left untouched.
int p256_ecdsa_verify(Qx, Qy, hash, r, s); // 0 = valid
int p384_ecdsa_verify(Qx, Qy, hash48, r, s);
int rsa_pkcs1_sha256_verify(N, Nlen, e, sig, siglen, hash);
int rsa_pss_sha256_verify(N, Nlen, e, sig, siglen, mHash);ClientHello → TLS 1.2, CSPRNG random, SNI, cipher list, supported_groups
← ServerHello (chosen cipher suite)
← Certificate (the chain)
← ServerKeyExchange (ECDHE params + signature)
← ServerHelloDone
│
├─ verify the chain to a pinned root (x509.c)
├─ check the hostname against the SAN (x509.c)
├─ check the validity dates against RTC (x509.c)
└─ verify the SKE signature under the leaf key
│
ClientKeyExchange → our ECDHE public value
ChangeCipherSpec →
Finished → verify_data over the handshake transcript
← ChangeCipherSpec
← Finished
═══════ AES-128-GCM application records ═══════
| Value | Suite |
|---|---|
0xC02F |
ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
0xC02B |
ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 |
0xC030 |
ECDHE_RSA_WITH_AES_256_GCM_SHA384 |
0xC02C |
ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 |
0x009C / 0x009D
|
RSA_WITH_AES_*_GCM_* |
0x002F / 0x0035
|
RSA_WITH_AES_*_CBC_SHA |
x25519, secp256r1 (P-256), secp384r1 (P-384). P-256 matters in practice — a large fraction of servers prefer it and will not negotiate x25519.
The TLS 1.2 PRF (P_SHA256) derives the master secret from the ECDHE pre-master secret and the two randoms, then expands it into the key block. Records are framed on the wire as:
explicit_nonce(8) || GCM_ciphertext || GCM_tag(16)
tlskeytest and tlsrectest check the schedule and the record layer, including the Finished verify_data, against known answers.
Chain verification takes the certificates the server sent, verifies each under the next one's public key, and requires the top to carry a pinned trusted-root public key from x509_roots.h.
| Result | Meaning |
|---|---|
X509_OK (0) |
Every link verified and the top is a pinned trusted root |
X509_INCOMPLETE (1) |
Links checked, but not anchored — unknown root or an unsupported signature algorithm. Not a detected forgery |
X509_FORGED (−1) |
A link using a supported algorithm failed cryptographic verification |
That three-way distinction is deliberate. "I could not check this" and "I checked this and it is forged" are different statements, and collapsing them would either cry wolf or hide an attack.
Two further checks complete "verify the peer":
-
x509_check_host— matchessubjectAltNamedNSName entries case-insensitively, honouring a single leading*.wildcard label -
x509_check_validity— checks the certificate is inside its validity window, per the RTC
Five, in x509_roots.h:
| Anchor | Key |
|---|---|
| SSL.com TLS ECC Root CA 2022 | EC |
| Amazon Root CA 1 | RSA-2048 |
| DigiCert Global G2 TLS RSA SHA256 2020 CA1 | RSA-2048 |
| GTS Root R4 | EC |
| Root YR | RSA-4096 |
chaintest runs a real chain (accept), a one-byte-tampered copy (reject as forged), and a root-less prefix (reject as not-anchored).
tlsstrict on
Off by default. When on, a handshake is refused unless:
- The chain anchors to a pinned root
- The hostname matches the certificate
- The certificate is in date
- The ServerKeyExchange signature verifies
With it off, failures are reported and the connection proceeds — useful for development, useless as a defence. Strict mode is what turns the trust model from "reported" into "blocked".
int tls_hello(const char* host, int iface_idx);
int tls_https_fetch(const char* host, const char* path, int iface_idx,
uint8_t* out, uint32_t cap, int verbose);
int tls_https_request(const char* host, const char* path, const char* method,
const uint8_t* body, uint32_t body_len, int iface_idx,
uint8_t* out, uint32_t cap, int verbose);
void tls_set_strict(int on);
int tls_get_strict(void);tls_https_request sends a non-NULL body as application/x-www-form-urlencoded with a Content-Length — this is what backs POST forms in Selene Browser.
Receiving is streaming, so pages larger than the record buffer load correctly.
tls example.com # handshake against host:443, with detail
tlsstrict on # then repeat — a failing chain now refuses
posttest # live HTTP POST over TLS to httpbin
httpget https://… # fetch and print
selene # the browser, over HTTPSThe whole stack was built in sequence between v5.9.48 and v5.9.80, one primitive per release — ClientHello, X25519, the PRF, ECDHE, AES-GCM, the record layer, a live handshake, then the trust model (DER, ECDSA-P256, RSA, SHA-512, ECDSA-P384, chain verification, hostname and dates), then enforcement and the wider trust store. Version History has the release-by-release account.
- Networking Stack - the TCP layer TLS runs over
- Selene Browser - the main consumer
- Security - the threat model and its limits
- Shell - the self-test commands
- RFC 5246 - TLS 1.2 - IETF
- RFC 7748 - Elliptic Curves for Security (X25519) - IETF
- RFC 8017 - PKCS #1 v2.2 (RSA) - IETF
- RFC 5280 - X.509 PKI Certificate Profile - IETF
- RFC 4231 - HMAC-SHA test vectors - IETF
- FIPS 180-4 - Secure Hash Standard - NIST
- FIPS 197 - AES - NIST
- SP 800-38D - GCM - NIST
- SP 800-90A - DRBGs - NIST
- FIPS 186-4 - Digital Signature Standard (P-256, P-384) - NIST
NyxOS v6.4.363 · GPL v2 · GitHub · uselessalter on Discord · nyxos@inbox.lv
NyxOS Wiki
Getting started
Kernel
Storage & network
Graphics & apps
Userspace
HOWTO
- HOWTO-Add-a-system-call
- HOWTO-Write-a-userspace-program
- HOWTO-Add-a-shell-command
- HOWTO-Add-a-GUI-application
Reference
- Syscall-Reference
- Command-Reference
- Hardware-Reference
- Format-Reference
- Kernel-Data-Structures
- Source-Tree-Reference
Project